diff -u --recursive --new-file v2.3.38/linux/CREDITS linux/CREDITS
--- v2.3.38/linux/CREDITS	Fri Jan  7 19:13:21 2000
+++ linux/CREDITS	Mon Jan 10 14:05:32 2000
@@ -539,6 +539,15 @@
 S: Blacksburg, Virginia 24061
 S: USA
 
+N: Randy Dunlap
+E: randy.dunlap@intel.com
+W: http://home.att.net/~randy.dunlap/
+W: http://www.linux-usb.org
+D: Linux-USB subsystem, USB core/UHCI/printer/storage drivers
+S: 5200 NE Elam Young Pkwy., M/S HF3-77
+S: Hillsboro, Oregon 97124
+S: USA
+
 N: Cyrus Durgin
 E: cider@speakeasy.org
 W: http://www.speakeasy.org/~cider/
@@ -896,9 +905,9 @@
 
 N: Jauder Ho
 E: jauderho@carumba.com
-W: http://www.carumba.com/~jauderho/
+W: http://www.carumba.com/
 D: bug toaster (A1 sauce makes all the difference)
-D: Transmeta BOFH in my copius free time
+D: Random linux hacker
 
 N: Dirk Hohndel
 E: hohndel@suse.de
@@ -1039,12 +1048,14 @@
 
 N: Dave Jones
 E: dave@powertweak.com
+E: djones2@glam.ac.uk
 W: http://linux.powertweak.com
-D: Centaur/IDT Winchip/Winchip 2 tweaks
+D: Moved PCI bridge tuning to userspace (Powertweak).
+D: Centaur/IDT Winchip/Winchip 2 tweaks.
 D: Misc clean ups and other random hacking.
-S: 40, Heol Edward Lewis,
-S: Gelligaer, Hengoed,
-S: Mid Glamorgan, CF82 8EJ,
+S: 28, Laura Street,
+S: Treforest, Pontypridd,
+S: Mid Glamorgan, CF37 1NW,
 S: Wales, United Kingdom
 
 N: Bernhard Kaindl
@@ -1444,9 +1455,9 @@
 D: miscellaneous Makefile & Config.in fixes
 D: Cyclom 2X synchronous card driver
 D: i18n for minicom, net-tools, util-linux, fetchmail, etc
-S: Conectiva Informática LTDA
-S: R. Prof. Rubens Elke Braga, 558 - Parolin
-S: 80220-320 Curitiba - Paraná
+S: Conectiva S.A.
+S: R. Tocantins, 89 - Cristo Rei
+S: 80050-430 - Curitiba - Paraná
 S: Brazil
 
 N: Michael Meskes
@@ -2057,13 +2068,13 @@
 
 N: Marcelo W. Tosatti
 E: marcelo@conectiva.com.br
-W: http://lie-br.conectiva.com.br/~marcelo/
+W: http://bazar.conectiva.com.br/~marcelo/
 D: Miscellaneous kernel hacker
-D: Cyclom 2X driver hacker
+D: Cyclom 2X driver, drbd hacker
 D: linuxconf apache & proftpd module maintainer
-S: Conectiva Informática LTDA
-S: R. Prof. Rubens Elke Braga, 558 - Parolin
-S: 80220-320 Curitiba - Paraná
+S: Conectiva S.A.
+S: R. Tocantins, 89 - Cristo Rei
+S: 80050-430 - Curitiba - Paraná
 S: Brazil
 
 N: Stefan Traby
@@ -2303,6 +2314,7 @@
 W: http://www-sigproc.eng.cam.ac.uk/~sjw44/
 D: Linux DECnet project: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html
 D: Minor debugging of other networking protocols.
+D: Misc bug fixes and filesystem development
 
 N: Hans-Joachim Widmaier
 E: hjw@zvw.de
diff -u --recursive --new-file v2.3.38/linux/Documentation/Changes linux/Documentation/Changes
--- v2.3.38/linux/Documentation/Changes	Fri Jan  7 19:13:21 2000
+++ linux/Documentation/Changes	Mon Jan 10 12:20:59 2000
@@ -319,13 +319,12 @@
 ==============
 
    As of 2.1.33, parallel port support can now by handled by the parport
-driver.  Be aware that with Plug-and-Play support turned on, your
-parallel port may no longer be where you expect it; for example, LPT1
-(under DOS) was sometimes /dev/lp1 in Linux, but will probably be
-/dev/lp0 with the new Plug-and-Play driver.  If printing breaks with
-the new driver, try checking your lpd configuration.  A good source of
-more information is the Documentation/parport.txt file included with
-the kernel.
+driver.  Be aware that your parallel port may no longer be where you
+expect it; for example, LPT1 (under DOS) was sometimes /dev/lp1 in
+Linux, but will probably be /dev/lp0 with the new parport driver.  If
+printing breaks with the new driver, try checking your lpd
+configuration.  A good source of more information is the
+Documentation/parport.txt file included with the kernel.
 
 Setserial
 =========
diff -u --recursive --new-file v2.3.38/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.38/linux/Documentation/Configure.help	Fri Jan  7 19:13:21 2000
+++ linux/Documentation/Configure.help	Mon Jan 10 18:25:32 2000
@@ -2241,8 +2241,8 @@
 CONFIG_FB_S3TRIO
   If you have a S3 Trio say Y. Say N for S3 Virge. 
 
-ATI Mach64 display support
-CONFIG_FB_ATY (EXPERIMENTAL)
+ATI Mach64 display support (EXPERIMENTAL)
+CONFIG_FB_ATY
   This driver supports graphics boards with the ATI Mach64 chips.
   Say Y if you have such a graphics board.
 
@@ -2250,6 +2250,16 @@
   inserted and removed from the running kernel whenever you want). The
   module will be called atyfb.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
+
+ATI Rage128 display support (EXPERIMENTAL)
+CONFIG_FB_ATY128
+  This driver supports graphics boards with the ATI Rage128 chips.
+  Say Y if you have such a graphics board.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called aty128fb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
   
 PowerMac "control" frame buffer device support
 CONFIG_FB_CONTROL
@@ -6360,7 +6370,7 @@
 Cyclom 2X(tm) multiprotocol cards (EXPERIMENTAL)
 CONFIG_CYCLADES_SYNC
   Cyclom 2X from Cyclades Corporation (http://www.cyclades.com and
-  http://www.cyclades.com.br ) is an intelligent multiprotocol WAN
+  http://www.cyclades.com.br) is an intelligent multiprotocol WAN
   adapter with data transfer rates up to 512 Kbps. These cards support
   the X.25 and SNA related protocols. If you have one or more of these
   cards, say Y to this option. The next questions will ask you about
@@ -6376,7 +6386,7 @@
   Feel free to contact me or the cycsyn-devel mailing list at
   acme@conectiva.com.br and cycsyn-devel@bazar.conectiva.com.br for
   additional details, I hope to have documentation available as soon
-  as possible.
+  as possible (Cyclades Brazil is writing the Documentation).
 
   The driver will be compiled as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -7308,7 +7318,7 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-  Please email feedback to james.banks@caldera.com.
+  Please email feedback to torben.mathiasen@compaq.com.
 
 VIA Rhine support
 CONFIG_VIA_RHINE
@@ -8038,12 +8048,9 @@
 USB OV511 Camera support
 CONFIG_USB_OV511
   Say Y here if you want to connect this type of camera to your
-  computer's USB port. See drivers/usb/README.ov511 for more
+  computer's USB port. See Documentation/usb/ov511.txt for more
   information and for a list of supported cameras.
   
-  NOTE: This code is experimental and you will not get video with it
-  yet.
-
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called ov511.o. If you want to compile it as a
@@ -8115,6 +8122,17 @@
   Note that you must say Y to global "/proc filesystem support" under
   Filesystems for this to work.
 
+USB device file system
+CONFIG_USB_DEVICEFS
+  This file system implements a "devices" file, that lists
+  the currently connected to your USB busses, a "drivers" file
+  that lists the USB kernel client drivers currently loaded,
+  and for every connected device a file named "xxx/yyy", where
+  xxx is the bus number and yyy the device number, that can be used
+  by userspace drivers to talk to the device.
+
+  Most users want to say Y here.
+
 DABUSB driver
 CONFIG_USB_DABUSB
   A Digital Audio Broadcasting (DAB) Receiver for USB and Linux brought
@@ -8597,11 +8615,11 @@
   If you don't know whether you need it, then you don't need it:
   answer N.
 
-QNX filesystem support (read only) (EXPERIMENTAL)
+QNX4 filesystem support (read only) (EXPERIMENTAL)
 CONFIG_QNX4FS_FS  
   This is the filesystem used by the operating system QNX 4. Say Y if
   you intend to mount QNX hard disks or floppies. Unless you say Y to
-  "QNXFS read-write support" below, you will only be able to read
+  "QNX4FS write support" below, you will only be able to read
   these filesystems.
 
   This filesystem support is also available as a module ( = code which
@@ -8609,11 +8627,12 @@
   want). The module is called qnx4.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt. 
 
-  If unsure, say N.
+  If you don't know whether you need it, then you don't need it:
+  answer N.
 
-QNXFS write support (DANGEROUS)
+QNX4FS write support (DANGEROUS)
 CONFIG_QNX4FS_RW
-  Say Y if you want to test write support for QNX filesystems.
+  Say Y if you want to test write support for QNX4 filesystems.
 
 Kernel automounter support
 CONFIG_AUTOFS_FS
@@ -12276,10 +12295,11 @@
 
 Processor Type
 CONFIG_6xx
-  There are two types of PowerPC chips supported. The more common
-  types (601,603,604,740,750) and the embedded versions (821 and 860).
-  Unless you are building a kernel for one of the embedded boards
-  using the 821 or 860 choose 6xx.
+  There are three types of PowerPC chips supported. The more common
+  types (601, 603, 604, 740, 750), the Motorola embedded versions (821,
+  823, 850, 855, 860), and the IBM embedded versions (403 and 405).
+  Unless you are building a kernel for one of the embedded processor
+  systems, choose 6xx.
 
 Machine Type
 CONFIG_PMAC
@@ -13520,7 +13540,7 @@
 # LocalWords:  ACTiSYS Dongle dongle dongles esi actisys IrMate tekram BVM MVME
 # LocalWords:  BVME BVME WRITETHROUGH copyback writethrough fwmark syncookie tu
 # LocalWords:  alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid
-# LocalWords:  QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
+# LocalWords:  QNX4FS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
 # LocalWords:  IrLPT UIRCC Tecra Strebel jstrebel suse Eichwalder ke INI INIA
 # LocalWords:  FCP qlogicfc sym isapnp DTLK DoubleTalk rcsys dtlk DMAP SGIVW ar
 # LocalWords:  dmabuf EcoRadio MUTEFREQ GIrBIL girbil tepkom vol mha diplom PQS
diff -u --recursive --new-file v2.3.38/linux/Documentation/fb/aty128fb.txt linux/Documentation/fb/aty128fb.txt
--- v2.3.38/linux/Documentation/fb/aty128fb.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/fb/aty128fb.txt	Mon Jan 10 12:17:37 2000
@@ -0,0 +1,72 @@
+[This file is cloned from VesaFB/matroxfb]
+
+What is aty128fb?
+=================
+
+This is a driver for a graphic framebuffer for ATI Rage128 based devices
+on Intel and PPC boxes.
+
+Advantages:
+
+ * It provides a nice large console (128 cols + 48 lines with 1024x768)
+   without using tiny, unreadable fonts.
+ * You can run XF68_FBDev on top of /dev/fb0
+ * Most important: boot logo :-)
+
+Disadvantages:
+
+ * graphic mode is slower than text mode... but you should not notice
+   if you use same resolution as you used in textmode.
+ * still experimental.
+
+
+How to use it?
+==============
+
+Switching modes is done using the  video=aty128fb:<resolution>... modedb
+boot parameter or using `fbset' program.
+
+See Documentation/fb/modedb.txt for more information on modedb
+resolutions.
+
+You should compile in both vgacon (to boot if you remove your Rage128 from
+box) and aty128fb (for graphics mode). You should not compile-in vesafb
+unless you have primary display on non-Rage128 VBE2.0 device (see 
+Documentation/vesafb.txt for details).
+
+
+X11
+===
+
+XF68_FBDev should generally work fine, but it is non-accelerated. As of
+this document, 8 and 32bpp works fine.  There have been palette issues
+when switching from X to console and back to X.  You will have to restart
+X to fix this.
+
+
+Configuration
+=============
+
+You can pass kernel command line options to vesafb with
+`video=aty128fb:option1,option2:value2,option3' (multiple options should
+be separated by comma, values are separated from options by `:'). 
+Accepted options:
+
+noaccel  - do not use acceleration engine. It is default.
+accel    - use acceleration engine. Not finished.
+vmode:x  - chooses PowerMacintosh video mode <x>. Depreciated.
+cmode:x  - chooses PowerMacintosh colour mode <x>. Depreciated.
+<XxX@X>  - selects startup videomode. See modedb.txt for detailed
+	   explanation. Default is 640x480x8bpp.
+
+
+Limitations
+===========
+
+There are known and unknown bugs, features and misfeatures.
+Currently there are following known bugs:
+ + This driver is still experimental and is not finished.  Too many
+   bugs/eratta to list here.
+
+--
+Brad Douglas <brad@neruo.com>
diff -u --recursive --new-file v2.3.38/linux/Documentation/highuid.txt linux/Documentation/highuid.txt
--- v2.3.38/linux/Documentation/highuid.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/highuid.txt	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,78 @@
+Notes on the change from 16-bit UIDs to 32-bit UIDs:
+
+- kernel code MUST take into account __kernel_uid_t and __kernel_uid32_t
+  when communicating between user and kernel space in an ioctl or data
+  structure.
+
+- kernel code should use uid_t and gid_t in kernel-private structures and
+  code.
+
+What's left to be done for 32-bit UIDs on all Linux architectures:
+
+- Disk quotas have an interesting limitation that is not related to the
+  maximum UID/GID. They are limited by the maximum file size on the
+  underlying filesystem, because quota records are written at offsets
+  corresponding to the UID in question.
+  Further investigation is needed to see if the quota system can cope
+  properly with huge UIDs. If it can deal with 64-bit file offsets on all 
+  architectures, this should not be a problem.
+
+- Decide on a final layout for the new msqid64_ds, semid64_ds, and
+  shmid64_ds, and shminfo64 structures. The current ones leave pad space
+  for 64-bit time_t and 32-bit pid_t, as well as 4 extra machine words.
+  Perhaps more pad space should be left for future use?
+
+- Decide whether or not to keep backwards compatibility with the system
+  accounting file, or if we should break it as the comments suggest
+  (currently, the old 16-bit UID and GID are still written to disk, and
+  part of the former pad sparce is used to store separate 32-bit UID and
+  GID)
+
+- Need to validate that OS emulation calls the 16-bit UID
+  compatibility syscalls, if the OS being emulated used 16-bit UIDs, or
+  uses the 32-bit UID system calls properly otherwise.
+
+  This affects at least:
+	SunOS emulation - now fixed?
+	Solaris emulation
+	iBCS on Intel
+
+	sparc32 emulation on sparc64
+	(need to support whatever new 32-bit UID system calls are added to
+	sparc32)
+
+- Validate that all filesystems behave properly.
+
+  At present, 32-bit UIDs _should_ work for:
+	ext2
+	ufs
+	isofs
+	nfs
+	coda
+	udf
+
+  Ioctl() fixups have been made for:
+	ncpfs
+	smbfs
+
+  Filesystems with simple fixups to prevent 16-bit UID wraparound:
+	minix
+	sysv
+	qnx4
+
+  Other filesystems have not been checked yet.
+
+- The ncpfs and smpfs filesystems can not presently return 32-bit UIDs to
+  all ioctl()s. Some new ioctl()s have been added for 32-bit UIDs, but
+  more are needed. (as well as new user<->kernel data structures)
+
+- The ELF core dump format only supports 16-bit UIDs on arm, i386, m68k,
+  sh, and sparc32. Fixing this is probably not that important, but would
+  require adding a new ELF section.
+
+- The ioctl()s used to control the in-kernel NFS server only support
+  16-bit UIDs on arm, i386, m68k, sh, and sparc32.
+
+- make sure that the UID mapping feature of AX25 networking works properly
+  (it should be safe because it's always used a 32-bit integer to
+  communicate between user and kernel)
diff -u --recursive --new-file v2.3.38/linux/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt
--- v2.3.38/linux/Documentation/networking/decnet.txt	Wed May 26 09:36:36 1999
+++ linux/Documentation/networking/decnet.txt	Sat Jan  8 21:36:20 2000
@@ -12,6 +12,8 @@
                 - Swansea University Computer Society DECnet Archive
                   (contains kernel patches and info)
                 - Mirror of userland tools on ftp.dreamtime.org
+                - Mirror of Alexey Kuznetsov's iproute2 package and
+                  other utilities
 
         ftp://ftp.dreamtime.org/pub/linux/decnet/
                 - Patrick Caulfield's archive of userland tools and
@@ -39,10 +41,16 @@
 
     decnet=1,2,1
 
-the first two numbers are the node address 1,2 = 1.2 (yes, you must use
-commas when specifying them). The third number is the level number for routers
-and is optional. It is probably a good idea to set the DECnet address on boot
-like this rather than trying to do it later.
+the first two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels
+and early 2.3.xx kernels, you must use a comma when specifying the
+DECnet address like this. For more recent 2.3.xx kernels, you may
+use almost charecter except space, although a `.` would be the most
+obvious choice :-)
+
+The third number is the level number for routers and is optional. In fact
+this option may go away shortly in favour if settings for each interface
+seperately. It is probably a good idea to set the DECnet address and type
+on boot like this rather than trying to do it later.
 
 There are also equivalent options for modules. The node address and type can
 also be set through the /proc/sys/net/decnet/ files, as can other system
@@ -71,7 +79,23 @@
 There is a list of what the other files under /proc/sys/net/decnet/ do
 on the kernel patch web site (shown above).
 
-4) How can I tell if its working ?
+4) Run time kernel configuration
+
+This is either done through the sysctl/proc interface (see the kernel web
+pages for details on what the various options do) or through the iproute2
+package in the same way as IPv4/6 configuration is performed.
+
+Documentation for iproute2 is included with the package, although there is
+as yet no specific section on DECnet, most of the features apply to both
+IP and DECnet, albeit with DECnet addresses instead of IP addresses and
+a reduced functionality.
+
+If you want to configure a DECnet router you'll need the iproute2 package
+since its the _only_ way to add and delete routes currently. Eventually
+there will be a routing daemon to send and receive routing messages for
+each interface and update the kernel routing tables accordingly.
+
+5) How can I tell if its working ?
 
 Here is a quick guide of what to look for in order to know if your DECnet
 kernel subsystem is working.
@@ -102,11 +126,11 @@
      network, and see if you can obtain the same results.
    - At this point you are on your own... :-)
 
-5) How to send a bug report
+6) How to send a bug report
 
 If you've found a bug and want to report it, then there are several things
 you can do to help me work out exactly what it is that is wrong. Useful
-information (a lot of which is essential) includes:
+information (_most_ of which _is_ _essential_) includes:
 
  - What kernel version are you running ?
  - What version of the patch are you running ?
@@ -121,10 +145,10 @@
  - How can the problem be reproduced ?
  - Can you use tcpdump to get a trace ? (N.B. Most (all?) versions of 
    tcpdump don't understand how to dump DECnet properly, so including
-   the hex listing of the packet contents is essential, usually the -x flag.
+   the hex listing of the packet contents is _essential_, usually the -x flag.
    You may also need to increase the length grabbed with the -s flag)
 
-6) Mailing list
+7) Mailing list
 
 If you are keen to get involved in development, or want to ask questions
 about configuration, or even just report bugs, then there is a mailing
@@ -134,7 +158,7 @@
 
 as the body of the message.
 
-7) Legal Info
+8) Legal Info
 
 The Linux DECnet project team have placed their code under the GPL. The
 software is provided "as is" and without warranty express or implied.
diff -u --recursive --new-file v2.3.38/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.3.38/linux/Documentation/networking/ip-sysctl.txt	Thu Jan  6 12:57:47 2000
+++ linux/Documentation/networking/ip-sysctl.txt	Sat Jan  8 21:36:20 2000
@@ -13,30 +13,10 @@
 ip_default_ttl - INTEGER
 	default 64
 
-ip_addrmask_agent - BOOLEAN
-	Reply to ICMP ADDRESS MASK requests.
-	default TRUE (router)
-		FALSE (host)
-
-ip_bootp_agent - BOOLEAN
-	Accept packets with source address of sort 0.b.c.d
-	and destined to this host, broadcast or multicast.
-	Such packets are silently ignored otherwise.
-
-	default FALSE
-
 ip_no_pmtu_disc - BOOLEAN
 	Disable Path MTU Discovery.
 	default FALSE
 
-ip_fib_model - INTEGER
-	0 - (DEFAULT) Standard model. All routes are in class MAIN.
-	1 - default routes go to class DEFAULT. This mode should
-	    be very convenient for small ISPs making policy routing.
-	2 - RFC1812 compliant model.
-	    Interface routes are in class MAIN.
-	    Gateway routes are in class DEFAULT.
-
 IP Fragmentation:
 
 ipfrag_high_thresh - INTEGER
@@ -187,18 +167,17 @@
 	Do proxy arp.
 
 shared_media - BOOLEAN
-	undocumented.
+	Send(router) or accept(host) RFC1620 shared media redirects.
+	Overrides ip_secure_redirects.
+	default TRUE
 
 secure_redirects - BOOLEAN
 	Accept ICMP redirect messages only for gateways,
 	listed in default gateway list.
 	default TRUE
 
-redirects - BOOLEAN
-	Send(router) or accept(host) RFC1620 shared media redirects.
-	Overrides ip_secure_redirects.
-	default TRUE (should be FALSE for distributed version,
-		      but I use it...)
+send_redirects - BOOLEAN
+	Send redirects, if router. Default: TRUE
 
 bootp_relay - BOOLEAN
 	Accept packets with source address 0.b.c.d destined
@@ -213,27 +192,17 @@
 	default TRUE (router)
 		FALSE (host)
 
-rp_filter - INTEGER
-	2 - do source validation by reversed path, as specified in RFC1812
+rp_filter - BOOLEAN
+	1 - do source validation by reversed path, as specified in RFC1812
 	    Recommended option for single homed hosts and stub network
 	    routers. Could cause troubles for complicated (not loop free)
 	    networks running a slow unreliable protocol (sort of RIP),
 	    or using static routes.
 
-	1 - (DEFAULT) Weaker form of RP filtering: drop all the packets
-	    that look as sourced at a directly connected interface, but
-	    were input from another interface.
-	    
 	0 - No source validation. 
 
-	NOTE: do not disable this option! All BSD derived routing software
-	(sort of gated, routed etc. etc.) is confused by such packets,
-	even if they are valid. When enabled it also prevents ip spoofing
-	in some limited fashion.
-
-	NOTE: this option is turned on per default only when ip_forwarding
-	is on. For non-forwarding hosts it doesn't make much sense and 
-	makes some legal multihoming configurations impossible.
+	Default value is 0. Note that some distribution enable it
+	in startip scripts.
 
 Alexey Kuznetsov.
 kuznet@ms2.inr.ac.ru
@@ -241,4 +210,4 @@
 Updated by:
 Andi Kleen
 ak@muc.de
-$Id: ip-sysctl.txt,v 1.10 2000/01/06 00:41:42 davem Exp $
+$Id: ip-sysctl.txt,v 1.11 2000/01/08 20:32:41 davem Exp $
diff -u --recursive --new-file v2.3.38/linux/Documentation/paride.txt linux/Documentation/paride.txt
--- v2.3.38/linux/Documentation/paride.txt	Tue Dec 22 08:29:00 1998
+++ linux/Documentation/paride.txt	Sat Jan  8 12:54:54 2000
@@ -356,7 +356,7 @@
 multiple device environments, the PARIDE drivers will not do it 
 automatically.  You can however, force a printer reset by doing:
 
-	insmod lp
+	insmod lp reset=1
 	rmmod lp
 
 If you have one of these marginal cases, you should probably build
diff -u --recursive --new-file v2.3.38/linux/Documentation/sysctl/fs.txt linux/Documentation/sysctl/fs.txt
--- v2.3.38/linux/Documentation/sysctl/fs.txt	Mon Jul  5 20:04:47 1999
+++ linux/Documentation/sysctl/fs.txt	Mon Jan 10 18:15:58 2000
@@ -23,6 +23,8 @@
 - inode-max
 - inode-nr
 - inode-state
+- overflowuid
+- overflowgid
 - super-max
 - super-nr
 
@@ -114,6 +116,18 @@
 preshrink is nonzero when the nr_inodes > inode-max and the
 system needs to prune the inode list instead of allocating
 more.
+
+==============================================================
+
+overflowgid & overflowuid:
+
+Some filesystems only support 16-bit UIDs and GIDs, although in Linux
+UIDs and GIDs are 32 bits. When one of these filesystems is mounted
+with writes enabled, any UID or GID that would exceed 65535 is translated
+to a fixed value before being written to disk.
+
+These sysctls allow you to change the value of the fixed UID and GID.
+The default is 65534.
 
 ==============================================================
 
diff -u --recursive --new-file v2.3.38/linux/Documentation/sysctl/kernel.txt linux/Documentation/sysctl/kernel.txt
--- v2.3.38/linux/Documentation/sysctl/kernel.txt	Mon Jul  5 20:04:47 1999
+++ linux/Documentation/sysctl/kernel.txt	Mon Jan 10 18:15:58 2000
@@ -28,6 +28,8 @@
 - modprobe                    ==> Documentation/kmod.txt
 - osrelease
 - ostype
+- overflowgid
+- overflowuid
 - panic
 - powersave-nap               [ PPC only ]
 - printk
@@ -123,6 +125,18 @@
 this is the fifth kernel built from this source base and the
 date behind it indicates the time the kernel was built.
 The only way to tune these values is to rebuild the kernel :-)
+
+==============================================================
+
+overflowgid & overflowuid:
+
+if your architecture did not always support 32-bit UIDs (i.e. arm, i386,
+m68k, sh, and sparc32), a fixed UID and GID will be returned to
+applications that use the old 16-bit UID/GID system calls, if the actual
+UID or GID would exceed 65535.
+
+These sysctls allow you to change the value of the fixed UID and GID.
+The default is 65534.
 
 ==============================================================
 
diff -u --recursive --new-file v2.3.38/linux/Documentation/usb/CREDITS linux/Documentation/usb/CREDITS
--- v2.3.38/linux/Documentation/usb/CREDITS	Thu Jan  6 12:57:47 2000
+++ linux/Documentation/usb/CREDITS	Mon Jan 10 11:32:48 2000
@@ -4,13 +4,16 @@
 order by last name).  I'm sure this list should be longer, its
 difficult to maintain, add yourself with a patch if desired.
 
+  Georg Acher <acher@informatik.tu-muenchen.de>
   Alan Cox <alan@lxorguk.ukuu.org.uk>
   Johannes Erdfelt <jerdfelt@sventech.com>
+  Deti Fliegl <deti@fliegl.de>
   ham <ham@unsuave.com>
   Bradley M Keryan <keryan@andrew.cmu.edu>
   Paul Mackerras <paulus@cs.anu.edu.au>
   David E. Nelson <dnelson@jump.net>
   Vojtech Pavlik <vojtech@suse.cz>
+  Thomas Sailer <sailer@ife.ee.ethz.ch>
   Gregory P. Smith <greg@electricrain.com>
   Linus Torvalds <torvalds@transmeta.com>
   Roman Weissgaerber <weissg@vienna.at>
diff -u --recursive --new-file v2.3.38/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt
--- v2.3.38/linux/Documentation/usb/ov511.txt	Thu Jan  6 12:57:47 2000
+++ linux/Documentation/usb/ov511.txt	Mon Jan 10 11:37:53 2000
@@ -4,20 +4,21 @@
 
 INTRODUCTION:
 
-This is a preliminary version of my OV511 Linux device driver. At the moment,
-it does not do much more than detect the chip and initialize it. As trivial
-as this sounds, it represents many hours of my work. Since OmniVision refused
-to release the full specs to me, I had to write code to probe out the register
-read/write commands. Some code is in place to allow a frame to be grabbed, but
-it is nowhere near complete.
+This is a preliminary version of my OV511 Linux device driver. Currently, it can
+grab a frame in black-and-white at 640x480 using the vidcat utility. Color,
+variable image size, and compatibility with other apps are currently under
+development.
 
 SUPPORTED CAMERAS:
-____________________________________________
-Manufacturer     | Model        | Custom ID 
------------------+--------------+-----------
-D-Link           | DSB-C300	    | 3
-Creative Labs    | WebCam 3     | 21
---------------------------------------------
+________________________________________________________
+Manufacturer     | Model          | Custom ID | Status
+-----------------+----------------+-----------+---------
+MediaForte       | MV300          | 0         | Untested
+D-Link           | DSB-C300	      | 3         | Working
+Creative Labs    | WebCam 3       | 21        | Working
+Lifeview         | RoboCam        |	100       | Untested
+AverMedia        | InterCam Elite | 102       | Untested
+--------------------------------------------------------
 
 Any camera using the OV511 and the OV7610 CCD should work with this driver. The
 driver only detects known cameras though, based on their custom id number. If
@@ -36,19 +37,6 @@
   
 WHAT NEEDS TO BE DONE:
 
-In short, a lot. 
-
-UPDATE:
-Currently, the control messages are working fine ("vendor commands"; for
-reading and writing the OV511 registers.) The I2C bus commands for reading and
-writing the camera (OV7610) registers are implemented and working, with at least
-one person's camera. The isochronous-in endpoint for video data is finally
-producing data, but since ov511_parse_data() is not implemented you will not see
-a picture yet.
-
-Support for specific CCD's will have to be implemented as well (such as the
-OV7610.) 
-
 The rest of the work will involve implementing support for all the different
 resolutions, color depths, etc. Also, while support for the OV511's proprietary
 lossy compression is apparently not necessary (the code currently disables it,)
@@ -66,5 +54,5 @@
 
 The code is based in no small part on the CPiA driver by Johannes Erdfelt,
 Randy Dunlap, and others. Big thanks to them for their pioneering work on that
-and the USB stack. Thanks to Bret Wallach for getting camera reg IO and ISOC
-working.
+and the USB stack. Thanks to Bret Wallach for getting camera reg IO , ISOC, and
+preliminary image capture working.
diff -u --recursive --new-file v2.3.38/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST
--- v2.3.38/linux/Documentation/video4linux/bttv/CARDLIST	Tue Jan  4 13:57:16 2000
+++ linux/Documentation/video4linux/bttv/CARDLIST	Sat Jan  8 12:54:54 2000
@@ -23,7 +23,7 @@
   card=21 - Lucky Star Image World ConferenceTV
   card=22 - Phoebe Tv Master + FM
   card=23 - Modular Technology MM205 PCTV, bt878
-  card=24 - Magic TView CPH061 (bt878)
+  card=24 - Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)
   card=25 - Terratec/Vobis TV-Boostar
   card=26 - Newer Hauppauge WinCam (bt878)
   card=27 - MAXI TV Video PCI2
@@ -32,8 +32,7 @@
   card=30 - FlyVideo 98
   card=31 - iProTV
   card=32 - Intel Create and Share PCI
-  card=33 - Askey/Typhoon/Anubis Magic TView
-  card=34 - Terratec TerraTValue
+  card=33 - Terratec TerraTValue
 
 tuner.o
   type=0 - Temic PAL
diff -u --recursive --new-file v2.3.38/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README
--- v2.3.38/linux/Documentation/video4linux/bttv/README	Fri Jan  7 19:13:21 2000
+++ linux/Documentation/video4linux/bttv/README	Sat Jan  8 12:54:54 2000
@@ -49,7 +49,7 @@
 MAKEDEV:	a script to create the special files for v4l
 CARDLIST:	List of all supported cards
 
-Loading just the bttv modules isn't enough for most cards.  The
+Loading just the bttv modules isn't enouth for most cards.  The
 drivers for the i2c tuner/sound chips must also be loaded.  bttv tries
 to load them automagically by calling request_module() now, but this
 obviously works only with kmod enabled.
diff -u --recursive --new-file v2.3.38/linux/Documentation/vm/locking linux/Documentation/vm/locking
--- v2.3.38/linux/Documentation/vm/locking	Tue Dec  7 09:32:39 1999
+++ linux/Documentation/vm/locking	Sat Jan  8 21:36:20 2000
@@ -8,14 +8,14 @@
 --------------------------------------
 
 Page stealers pick processes out of the process pool and scan for 
-the best process to steal pages from. To guarantee the existance 
+the best process to steal pages from. To guarantee the existence 
 of the victim mm, a mm_count inc and a mmdrop are done in swap_out().
 Page stealers hold kernel_lock to protect against a bunch of races.
 The vma list of the victim mm is also scanned by the stealer, 
 and the vmlist_lock is used to preserve list sanity against the
-process adding/deleting to the list. This also gurantees existance
-of the vma. Vma existance is not guranteed once try_to_swap_out() 
-drops the vmlist lock. To gurantee the existance of the underlying 
+process adding/deleting to the list. This also guarantees existence
+of the vma. Vma existence is not guaranteed once try_to_swap_out() 
+drops the vmlist lock. To guarantee the existence of the underlying 
 file structure, a get_file is done before the swapout() method is 
 invoked. The page passed into swapout() is guaranteed not to be reused
 for a different purpose because the page reference count due to being
@@ -102,7 +102,7 @@
 array, and the "highest_bit" and "lowest_bit" fields.
 
 Both of these are spinlocks, and are never acquired from intr level. The
-locking heirarchy is swap_list_lock -> swap_device_lock.
+locking hierarchy is swap_list_lock -> swap_device_lock.
 
 To prevent races between swap space deletion or async readahead swapins
 deciding whether a swap handle is being used, ie worthy of being read in
diff -u --recursive --new-file v2.3.38/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.38/linux/MAINTAINERS	Fri Jan  7 19:13:21 2000
+++ linux/MAINTAINERS	Mon Jan 10 14:19:46 2000
@@ -264,9 +264,8 @@
 DECnet NETWORK LAYER
 P:	Steven Whitehouse
 M:	SteveW@ACM.org
-W:	http://www.sucs.swan.ac.uk/~rohan/
-W:	http://www-sigproc.eng.cam.ac.uk/~sjw44/
-L:	netdev@oss.sgi.com
+W:	http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html
+L:	linux-decnet@dreamtime.org
 S:	Maintained
 
 DEVICE NUMBER REGISTRY
@@ -754,9 +753,23 @@
 W:	http://www.pnd-pc.demon.co.uk/promise/
 S:	Maintained
 
+RAGE128 FRAMEBUFFER DISPLAY DRIVER
+P:	Brad Douglas
+M:	brad@neruo.com
+P:	Anthony Tong
+M:	atong@uiuc.edu
+L:	linux-fbdev@vcuser.vc.union.edu
+S:	Maintained
+
 RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
 P:	Corey Thomas
 M:	corey@world.std.com
+L:	linux-kernel@vger.rutgers.edu
+S:	Maintained
+
+QNX4 FILESYSTEM
+P:	Anders Larsen
+M:	al@alarsen.net
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
diff -u --recursive --new-file v2.3.38/linux/Makefile linux/Makefile
--- v2.3.38/linux/Makefile	Fri Jan  7 19:13:21 2000
+++ linux/Makefile	Sat Jan  8 21:33:52 2000
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 38
+SUBLEVEL = 39
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -203,7 +203,7 @@
 endif
 
 ifeq ($(CONFIG_PNP),y)
-DRIVERS := $(DRIVERS) drivers/pnp/pnp.a
+DRIVERS := $(DRIVERS) drivers/pnp/isa-pnp.o
 endif
 
 ifdef CONFIG_SGI
@@ -227,7 +227,7 @@
 endif
 
 ifeq ($(CONFIG_USB),y)
-DRIVERS := $(DRIVERS) drivers/usb/usb.a
+DRIVERS := $(DRIVERS) drivers/usb/usbdrv.o
 endif
 
 ifeq ($(CONFIG_I2O),y)
diff -u --recursive --new-file v2.3.38/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.3.38/linux/arch/alpha/kernel/entry.S	Tue Jan  4 13:57:16 2000
+++ linux/arch/alpha/kernel/entry.S	Mon Jan 10 18:15:58 2000
@@ -985,9 +985,9 @@
 	.quad osf_utsname
 	.quad sys_lchown
 	.quad osf_shmat
-	.quad sys_shmctlold			/* 210 */
+	.quad sys_shmctl			/* 210 */
 	.quad sys_shmdt
-	.quad sys_shmget
+	.quad osf_shmget
 	.quad alpha_ni_syscall
 	.quad alpha_ni_syscall
 	.quad alpha_ni_syscall			/* 215 */
@@ -1150,4 +1150,4 @@
 	.quad sys_setresgid
 	.quad sys_getresgid
 	.quad sys_ni_syscall			/* sys_dipc */
-	.quad sys_shmctl
+	.quad sys_shmget
diff -u --recursive --new-file v2.3.38/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.38/linux/arch/alpha/kernel/osf_sys.c	Fri Jan  7 19:13:21 2000
+++ linux/arch/alpha/kernel/osf_sys.c	Mon Jan 10 18:15:58 2000
@@ -1401,102 +1401,7 @@
 	return ret;
 }
 
-struct shmid_ds_old {
-	struct ipc_perm		shm_perm;	/* operation perms */
-	int			shm_segsz;	/* size of segment (bytes) */
-	__kernel_time_t		shm_atime;	/* last attach time */
-	__kernel_time_t		shm_dtime;	/* last detach time */
-	__kernel_time_t		shm_ctime;	/* last change time */
-	__kernel_ipc_pid_t	shm_cpid;	/* pid of creator */
-	__kernel_ipc_pid_t	shm_lpid;	/* pid of last operator */
-	unsigned short		shm_nattch;	/* no. of current attaches */
-	unsigned short 		shm_unused;	/* compatibility */
-	void 			*shm_unused2;	/* ditto - used by DIPC */
-	void			*shm_unused3;	/* unused */
-};
-
-struct  shminfo_old {
-	int shmmax;
-	int shmmin;
-	int shmmni;
-	int shmseg;
-	int shmall;
-};
-
-asmlinkage long sys_shmctlold(int shmid, int cmd, struct shmid_ds_old *buf)
+asmlinkage long osf_shmget (key_t key, int size, int flag)
 {
-	struct shmid_ds arg;
-	long ret;
-	mm_segment_t old_fs;
-
-	if (cmd == IPC_SET) {
-		struct shmid_ds_old tbuf;
-
-		if(copy_from_user (&tbuf, buf, sizeof(*buf)))
-			return -EFAULT;
-		arg.shm_perm = tbuf.shm_perm;
-		arg.shm_segsz = tbuf.shm_segsz;
-		arg.shm_atime = tbuf.shm_atime;
-		arg.shm_dtime = tbuf.shm_dtime;
-		arg.shm_ctime = tbuf.shm_ctime;
-		arg.shm_cpid = tbuf.shm_cpid;
-		arg.shm_lpid = tbuf.shm_lpid;
-		arg.shm_nattch = tbuf.shm_nattch;
-		arg.shm_unused = tbuf.shm_unused;
-		arg.shm_unused2 = tbuf.shm_unused2;
-		arg.shm_unused3 = tbuf.shm_unused3;
-	}
-	old_fs = get_fs ();
-	set_fs (KERNEL_DS);
-	ret = sys_shmctl(shmid, cmd, &arg);
-	set_fs (old_fs);
-	if (ret < 0)
-		return(ret);
-	switch(cmd) {
-		case IPC_INFO:
-		{
-			struct shminfo *tbuf = (struct shminfo *) &arg;
-			struct shminfo_old shminfo_oldst;
-
-			shminfo_oldst.shmmax = (tbuf->shmmax > INT_MAX ?
-						INT_MAX : tbuf->shmmax);
-			shminfo_oldst.shmmin = tbuf->shmmin;
-			shminfo_oldst.shmmni = tbuf->shmmni;
-			shminfo_oldst.shmseg = tbuf->shmseg;
-			shminfo_oldst.shmall = tbuf->shmall;
-			if (copy_to_user(buf, &shminfo_oldst, 
-						sizeof(struct shminfo_old)))
-				return -EFAULT;
-			return(ret);
-		}
-		case SHM_INFO:
-		{
-			struct shm_info *tbuf = (struct shm_info *) &arg;
-
-			if (copy_to_user (buf, tbuf, sizeof(struct shm_info)))
-				return -EFAULT;
-			return(ret);
-		}
-		case SHM_STAT:
-		case IPC_STAT:
-		{
-			struct shmid_ds_old tbuf;
-
-			tbuf.shm_perm = arg.shm_perm;
-			tbuf.shm_segsz = arg.shm_segsz;
-			tbuf.shm_atime = arg.shm_atime;
-			tbuf.shm_dtime = arg.shm_dtime;
-			tbuf.shm_ctime = arg.shm_ctime;
-			tbuf.shm_cpid = arg.shm_cpid;
-			tbuf.shm_lpid = arg.shm_lpid;
-			tbuf.shm_nattch = arg.shm_nattch;
-			tbuf.shm_unused = arg.shm_unused;
-			tbuf.shm_unused2 = arg.shm_unused2;
-			tbuf.shm_unused3 = arg.shm_unused3;
-			if (copy_to_user (buf, &tbuf, sizeof(tbuf)))
-				return -EFAULT;
-			return(ret);
-		}
-	}
-	return(ret);
+	return sys_shmget (key, size, flag);
 }
diff -u --recursive --new-file v2.3.38/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S
--- v2.3.38/linux/arch/arm/kernel/calls.S	Mon Dec 20 18:48:21 1999
+++ linux/arch/arm/kernel/calls.S	Mon Jan 10 18:15:58 2000
@@ -25,15 +25,15 @@
 		.long	SYMBOL_NAME(sys_time)
 		.long	SYMBOL_NAME(sys_mknod)
 /* 15 */	.long	SYMBOL_NAME(sys_chmod)
-		.long	SYMBOL_NAME(sys_lchown)
+		.long	SYMBOL_NAME(sys_lchown16)
 		.long	SYMBOL_NAME(sys_ni_syscall)		/* was sys_break */
 		.long	SYMBOL_NAME(sys_stat)
 		.long	SYMBOL_NAME(sys_lseek)
 /* 20 */	.long	SYMBOL_NAME(sys_getpid)
 		.long	SYMBOL_NAME(sys_mount_wrapper)
 		.long	SYMBOL_NAME(sys_oldumount)
-		.long	SYMBOL_NAME(sys_setuid)
-		.long	SYMBOL_NAME(sys_getuid)
+		.long	SYMBOL_NAME(sys_setuid16)
+		.long	SYMBOL_NAME(sys_getuid16)
 /* 25 */	.long	SYMBOL_NAME(sys_stime)
 		.long	SYMBOL_NAME(sys_ptrace)
 		.long	SYMBOL_NAME(sys_alarm)
@@ -55,11 +55,11 @@
 		.long	SYMBOL_NAME(sys_times)
 		.long	SYMBOL_NAME(sys_ni_syscall)		/* was sys_prof */
 /* 45 */	.long	SYMBOL_NAME(sys_brk)
-		.long	SYMBOL_NAME(sys_setgid)
-		.long	SYMBOL_NAME(sys_getgid)
+		.long	SYMBOL_NAME(sys_setgid16)
+		.long	SYMBOL_NAME(sys_getgid16)
 		.long	SYMBOL_NAME(sys_signal)
-		.long	SYMBOL_NAME(sys_geteuid)
-/* 50 */	.long	SYMBOL_NAME(sys_getegid)
+		.long	SYMBOL_NAME(sys_geteuid16)
+/* 50 */	.long	SYMBOL_NAME(sys_getegid16)
 		.long	SYMBOL_NAME(sys_acct)
 		.long	SYMBOL_NAME(sys_umount)
 		.long	SYMBOL_NAME(sys_ni_syscall)		/* was sys_lock */
@@ -79,8 +79,8 @@
 		.long	SYMBOL_NAME(sys_sigaction)
 		.long	SYMBOL_NAME(sys_sgetmask)
 		.long	SYMBOL_NAME(sys_ssetmask)
-/* 70 */	.long	SYMBOL_NAME(sys_setreuid)
-		.long	SYMBOL_NAME(sys_setregid)
+/* 70 */	.long	SYMBOL_NAME(sys_setreuid16)
+		.long	SYMBOL_NAME(sys_setregid16)
 		.long	SYMBOL_NAME(sys_sigsuspend_wrapper)
 		.long	SYMBOL_NAME(sys_sigpending)
 		.long	SYMBOL_NAME(sys_sethostname)
@@ -89,8 +89,8 @@
 		.long	SYMBOL_NAME(sys_getrusage)
 		.long	SYMBOL_NAME(sys_gettimeofday)
 		.long	SYMBOL_NAME(sys_settimeofday)
-/* 80 */	.long	SYMBOL_NAME(sys_getgroups)
-		.long	SYMBOL_NAME(sys_setgroups)
+/* 80 */	.long	SYMBOL_NAME(sys_getgroups16)
+		.long	SYMBOL_NAME(sys_setgroups16)
 		.long	SYMBOL_NAME(old_select)
 		.long	SYMBOL_NAME(sys_symlink)
 		.long	SYMBOL_NAME(sys_lstat)
@@ -104,7 +104,7 @@
 		.long	SYMBOL_NAME(sys_truncate)
 		.long	SYMBOL_NAME(sys_ftruncate)
 		.long	SYMBOL_NAME(sys_fchmod)
-/* 95 */	.long	SYMBOL_NAME(sys_fchown)
+/* 95 */	.long	SYMBOL_NAME(sys_fchown16)
 		.long	SYMBOL_NAME(sys_getpriority)
 		.long	SYMBOL_NAME(sys_setpriority)
 		.long	SYMBOL_NAME(sys_ni_syscall)		/* was sys_profil */
@@ -147,8 +147,8 @@
 /* 135 */	.long	SYMBOL_NAME(sys_sysfs)
 		.long	SYMBOL_NAME(sys_personality)
 		.long	SYMBOL_NAME(sys_ni_syscall)		/* .long	_sys_afs_syscall */
-		.long	SYMBOL_NAME(sys_setfsuid)
-		.long	SYMBOL_NAME(sys_setfsgid)
+		.long	SYMBOL_NAME(sys_setfsuid16)
+		.long	SYMBOL_NAME(sys_setfsgid16)
 /* 140 */	.long	SYMBOL_NAME(sys_llseek_wrapper)
 		.long	SYMBOL_NAME(sys_getdents)
 		.long	SYMBOL_NAME(sys_select)
@@ -173,14 +173,14 @@
 		.long	SYMBOL_NAME(sys_sched_rr_get_interval)
 		.long	SYMBOL_NAME(sys_nanosleep)
 		.long	SYMBOL_NAME(sys_mremap)
-		.long	SYMBOL_NAME(sys_setresuid)
-/* 165 */	.long	SYMBOL_NAME(sys_getresuid)
+		.long	SYMBOL_NAME(sys_setresuid16)
+/* 165 */	.long	SYMBOL_NAME(sys_getresuid16)
 		.long	SYMBOL_NAME(sys_ni_syscall)
 		.long	SYMBOL_NAME(sys_query_module)
 		.long	SYMBOL_NAME(sys_poll)
 		.long	SYMBOL_NAME(sys_nfsservctl)
-/* 170 */	.long	SYMBOL_NAME(sys_setresgid)
-		.long	SYMBOL_NAME(sys_getresgid)
+/* 170 */	.long	SYMBOL_NAME(sys_setresgid16)
+		.long	SYMBOL_NAME(sys_getresgid16)
 		.long	SYMBOL_NAME(sys_prctl)
 		.long	SYMBOL_NAME(sys_rt_sigreturn_wrapper)
 		.long	SYMBOL_NAME(sys_rt_sigaction)
@@ -191,7 +191,7 @@
 		.long	SYMBOL_NAME(sys_rt_sigsuspend_wrapper)
 /* 180 */	.long	SYMBOL_NAME(sys_pread)
 		.long	SYMBOL_NAME(sys_pwrite)
-		.long	SYMBOL_NAME(sys_chown)
+		.long	SYMBOL_NAME(sys_chown16)
 		.long	SYMBOL_NAME(sys_getcwd)
 		.long	SYMBOL_NAME(sys_capget)
 /* 185 */	.long	SYMBOL_NAME(sys_capset)
@@ -207,8 +207,27 @@
 /* 195 */	.long	SYMBOL_NAME(sys_stat64)
 		.long	SYMBOL_NAME(sys_lstat64)
 		.long	SYMBOL_NAME(sys_fstat64)
+		.long	SYMBOL_NAME(sys_lchown)
+		.long	SYMBOL_NAME(sys_getuid)
+/* 200 */	.long	SYMBOL_NAME(sys_getgid)
+		.long	SYMBOL_NAME(sys_geteuid)
+		.long	SYMBOL_NAME(sys_getegid)
+		.long	SYMBOL_NAME(sys_setreuid)
+		.long	SYMBOL_NAME(sys_setregid)
+/* 205 */	.long	SYMBOL_NAME(sys_getgroups)
+		.long	SYMBOL_NAME(sys_setgroups)
+		.long	SYMBOL_NAME(sys_fchown)
+		.long	SYMBOL_NAME(sys_setresuid)
+		.long	SYMBOL_NAME(sys_getresuid)
+/* 210 */	.long	SYMBOL_NAME(sys_setresgid)
+		.long	SYMBOL_NAME(sys_getresgid)
+		.long	SYMBOL_NAME(sys_chown)
+		.long	SYMBOL_NAME(sys_setuid)
+		.long	SYMBOL_NAME(sys_setgid)
+/* 215 */	.long	SYMBOL_NAME(sys_setfsuid)
+		.long	SYMBOL_NAME(sys_setfsgid)
 
-		.rept	NR_syscalls-197
+		.rept	NR_syscalls-216
 			.long	SYMBOL_NAME(sys_ni_syscall)
 		.endr
 #endif
diff -u --recursive --new-file v2.3.38/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c
--- v2.3.38/linux/arch/arm/kernel/signal.c	Tue Nov 23 22:42:20 1999
+++ linux/arch/arm/kernel/signal.c	Mon Jan 10 18:15:58 2000
@@ -18,6 +18,7 @@
 #include <linux/stddef.h>
 #include <linux/binfmts.h>
 #include <linux/tty.h>
+#include <linux/highuid.h>
 
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
@@ -500,6 +501,7 @@
 				info.si_code = SI_USER;
 				info.si_pid = current->p_pptr->pid;
 				info.si_uid = current->p_pptr->uid;
+				info.si_uid16 = high2lowuid(current->p_pptr->uid);
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
diff -u --recursive --new-file v2.3.38/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.38/linux/arch/i386/defconfig	Tue Jan  4 13:57:16 2000
+++ linux/arch/i386/defconfig	Sat Jan  8 13:16:30 2000
@@ -59,7 +59,6 @@
 #
 CONFIG_PCMCIA=y
 CONFIG_CARDBUS=y
-CONFIG_YENTA=y
 # CONFIG_I82365 is not set
 CONFIG_TCIC=y
 CONFIG_SYSVIPC=y
@@ -314,6 +313,7 @@
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_AIRONET4500_CS is not set
+# CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_3C575 is not set
 # CONFIG_PCMCIA_TULIP is not set
 # CONFIG_PCMCIA_EPIC100 is not set
@@ -401,6 +401,7 @@
 #
 # PCMCIA character device support
 #
+CONFIG_PCMCIA_SERIAL=y
 # CONFIG_PCMCIA_SERIAL_CS is not set
 # CONFIG_PCMCIA_SERIAL_CB is not set
 
diff -u --recursive --new-file v2.3.38/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.3.38/linux/arch/i386/kernel/entry.S	Mon Dec 20 18:48:21 1999
+++ linux/arch/i386/kernel/entry.S	Mon Jan 10 18:15:58 2000
@@ -416,15 +416,15 @@
 	.long SYMBOL_NAME(sys_time)
 	.long SYMBOL_NAME(sys_mknod)
 	.long SYMBOL_NAME(sys_chmod)		/* 15 */
-	.long SYMBOL_NAME(sys_lchown)
+	.long SYMBOL_NAME(sys_lchown16)
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old break syscall holder */
 	.long SYMBOL_NAME(sys_stat)
 	.long SYMBOL_NAME(sys_lseek)
 	.long SYMBOL_NAME(sys_getpid)		/* 20 */
 	.long SYMBOL_NAME(sys_mount)
 	.long SYMBOL_NAME(sys_oldumount)
-	.long SYMBOL_NAME(sys_setuid)
-	.long SYMBOL_NAME(sys_getuid)
+	.long SYMBOL_NAME(sys_setuid16)
+	.long SYMBOL_NAME(sys_getuid16)
 	.long SYMBOL_NAME(sys_stime)		/* 25 */
 	.long SYMBOL_NAME(sys_ptrace)
 	.long SYMBOL_NAME(sys_alarm)
@@ -446,11 +446,11 @@
 	.long SYMBOL_NAME(sys_times)
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old prof syscall holder */
 	.long SYMBOL_NAME(sys_brk)		/* 45 */
-	.long SYMBOL_NAME(sys_setgid)
-	.long SYMBOL_NAME(sys_getgid)
+	.long SYMBOL_NAME(sys_setgid16)
+	.long SYMBOL_NAME(sys_getgid16)
 	.long SYMBOL_NAME(sys_signal)
-	.long SYMBOL_NAME(sys_geteuid)
-	.long SYMBOL_NAME(sys_getegid)		/* 50 */
+	.long SYMBOL_NAME(sys_geteuid16)
+	.long SYMBOL_NAME(sys_getegid16)	/* 50 */
 	.long SYMBOL_NAME(sys_acct)
 	.long SYMBOL_NAME(sys_umount)					/* recycled never used phys() */
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old lock syscall holder */
@@ -470,8 +470,8 @@
 	.long SYMBOL_NAME(sys_sigaction)
 	.long SYMBOL_NAME(sys_sgetmask)
 	.long SYMBOL_NAME(sys_ssetmask)
-	.long SYMBOL_NAME(sys_setreuid)		/* 70 */
-	.long SYMBOL_NAME(sys_setregid)
+	.long SYMBOL_NAME(sys_setreuid16)	/* 70 */
+	.long SYMBOL_NAME(sys_setregid16)
 	.long SYMBOL_NAME(sys_sigsuspend)
 	.long SYMBOL_NAME(sys_sigpending)
 	.long SYMBOL_NAME(sys_sethostname)
@@ -480,8 +480,8 @@
 	.long SYMBOL_NAME(sys_getrusage)
 	.long SYMBOL_NAME(sys_gettimeofday)
 	.long SYMBOL_NAME(sys_settimeofday)
-	.long SYMBOL_NAME(sys_getgroups)	/* 80 */
-	.long SYMBOL_NAME(sys_setgroups)
+	.long SYMBOL_NAME(sys_getgroups16)	/* 80 */
+	.long SYMBOL_NAME(sys_setgroups16)
 	.long SYMBOL_NAME(old_select)
 	.long SYMBOL_NAME(sys_symlink)
 	.long SYMBOL_NAME(sys_lstat)
@@ -495,7 +495,7 @@
 	.long SYMBOL_NAME(sys_truncate)
 	.long SYMBOL_NAME(sys_ftruncate)
 	.long SYMBOL_NAME(sys_fchmod)
-	.long SYMBOL_NAME(sys_fchown)		/* 95 */
+	.long SYMBOL_NAME(sys_fchown16)		/* 95 */
 	.long SYMBOL_NAME(sys_getpriority)
 	.long SYMBOL_NAME(sys_setpriority)
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old profil syscall holder */
@@ -538,8 +538,8 @@
 	.long SYMBOL_NAME(sys_sysfs)		/* 135 */
 	.long SYMBOL_NAME(sys_personality)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* for afs_syscall */
-	.long SYMBOL_NAME(sys_setfsuid)
-	.long SYMBOL_NAME(sys_setfsgid)
+	.long SYMBOL_NAME(sys_setfsuid16)
+	.long SYMBOL_NAME(sys_setfsgid16)
 	.long SYMBOL_NAME(sys_llseek)		/* 140 */
 	.long SYMBOL_NAME(sys_getdents)
 	.long SYMBOL_NAME(sys_select)
@@ -564,14 +564,14 @@
 	.long SYMBOL_NAME(sys_sched_rr_get_interval)
 	.long SYMBOL_NAME(sys_nanosleep)
 	.long SYMBOL_NAME(sys_mremap)
-	.long SYMBOL_NAME(sys_setresuid)
-	.long SYMBOL_NAME(sys_getresuid)	/* 165 */
+	.long SYMBOL_NAME(sys_setresuid16)
+	.long SYMBOL_NAME(sys_getresuid16)	/* 165 */
 	.long SYMBOL_NAME(sys_vm86)
 	.long SYMBOL_NAME(sys_query_module)
 	.long SYMBOL_NAME(sys_poll)
 	.long SYMBOL_NAME(sys_nfsservctl)
-	.long SYMBOL_NAME(sys_setresgid)	/* 170 */
-	.long SYMBOL_NAME(sys_getresgid)
+	.long SYMBOL_NAME(sys_setresgid16)	/* 170 */
+	.long SYMBOL_NAME(sys_getresgid16)
 	.long SYMBOL_NAME(sys_prctl)
 	.long SYMBOL_NAME(sys_rt_sigreturn)
 	.long SYMBOL_NAME(sys_rt_sigaction)
@@ -582,7 +582,7 @@
 	.long SYMBOL_NAME(sys_rt_sigsuspend)
 	.long SYMBOL_NAME(sys_pread)		/* 180 */
 	.long SYMBOL_NAME(sys_pwrite)
-	.long SYMBOL_NAME(sys_chown)
+	.long SYMBOL_NAME(sys_chown16)
 	.long SYMBOL_NAME(sys_getcwd)
 	.long SYMBOL_NAME(sys_capget)
 	.long SYMBOL_NAME(sys_capset)           /* 185 */
@@ -598,6 +598,25 @@
 	.long SYMBOL_NAME(sys_stat64)		/* 195 */
 	.long SYMBOL_NAME(sys_lstat64)
 	.long SYMBOL_NAME(sys_fstat64)
+	.long SYMBOL_NAME(sys_lchown)
+	.long SYMBOL_NAME(sys_getuid)
+	.long SYMBOL_NAME(sys_getgid)		/* 200 */
+	.long SYMBOL_NAME(sys_geteuid)
+	.long SYMBOL_NAME(sys_getegid)
+	.long SYMBOL_NAME(sys_setreuid)
+	.long SYMBOL_NAME(sys_setregid)
+	.long SYMBOL_NAME(sys_getgroups)	/* 205 */
+	.long SYMBOL_NAME(sys_setgroups)
+	.long SYMBOL_NAME(sys_fchown)
+	.long SYMBOL_NAME(sys_setresuid)
+	.long SYMBOL_NAME(sys_getresuid)
+	.long SYMBOL_NAME(sys_setresgid)	/* 210 */
+	.long SYMBOL_NAME(sys_getresgid)
+	.long SYMBOL_NAME(sys_chown)
+	.long SYMBOL_NAME(sys_setuid)
+	.long SYMBOL_NAME(sys_setgid)
+	.long SYMBOL_NAME(sys_setfsuid)		/* 215 */
+	.long SYMBOL_NAME(sys_setfsgid)
 
 
 	/*
@@ -606,6 +625,6 @@
 	 * entries. Don't panic if you notice that this hasn't
 	 * been shrunk every time we add a new system call.
 	 */
-	.rept NR_syscalls-197
+	.rept NR_syscalls-216
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
diff -u --recursive --new-file v2.3.38/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.38/linux/arch/i386/kernel/setup.c	Fri Jan  7 19:13:21 2000
+++ linux/arch/i386/kernel/setup.c	Mon Jan 10 14:05:32 2000
@@ -31,6 +31,11 @@
  *
  *	Added proper L2 cache detection for Coppermine
  *	Dragan Stancevic <visitor@valinux.com>, October 1999
+ *
+ *  Added the origninal array for capability flags but forgot to credit 
+ *  myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff
+ *  	Jauder Ho <jauderho@carumba.com>, January 2000
+ *  	
  */
 
 /*
@@ -1166,6 +1171,8 @@
 		c->x86_vendor = X86_VENDOR_CENTAUR;
 	else if (!strcmp(v, "NexGenDriven"))
 		c->x86_vendor = X86_VENDOR_NEXGEN;
+	else if (!strcmp(v, "RiseRiseRise"))
+		c->x86_vendor = X86_VENDOR_RISE;
 	else
 		c->x86_vendor = X86_VENDOR_UNKNOWN;
 }
@@ -1176,6 +1183,7 @@
 	char *model_names[16];
 };
 
+/* Naming convention should be: <Name> [(<Codename>)] */
 static struct cpu_model_info cpu_models[] __initdata = {
 	{ X86_VENDOR_INTEL,	4,
 	  { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", 
@@ -1188,8 +1196,9 @@
 	    NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_INTEL,	6,
 	  { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
-	    NULL, "Pentium II (Deschutes)", "Mobile Pentium II", "Pentium III (Katmai)",
-	    "Pentium III (Coppermine)", NULL, NULL, NULL, NULL, NULL, NULL }},
+	    NULL, "Pentium II (Deschutes)", "Mobile Pentium II",
+	    "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
+	    NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_AMD,	4,
 	  { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
 	    "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
@@ -1210,6 +1219,9 @@
 	{ X86_VENDOR_NEXGEN,	5,
 	  { "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 }},
 };
 
 void __init identify_cpu(struct cpuinfo_x86 *c)
@@ -1300,8 +1312,9 @@
 			if (c->x86_model <= 16)
 				p = cpu_models[i].model_names[c->x86_model];
 
-			/* Names for the Pentium II Celeron processors 
-                           detectable only by also checking the cache size */
+			/* Names for the Pentium II/Celeron processors 
+                           detectable only by also checking the cache size.
+			   Dixon is NOT a Celeron. */
 			if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
 			    && (cpu_models[i].x86 == 6))
 			{
@@ -1310,7 +1323,7 @@
 				else if(c->x86_model == 6 && c->x86_cache_size == 128)
                             		p = "Celeron (Mendocino)"; 
  			  	else if(c->x86_model == 5 && c->x86_cache_size == 256)
-					p = "Celeron (Dixon)";
+					p = "Mobile Pentium II (Dixon)";
 			}
 		}
 	}
@@ -1341,7 +1354,7 @@
 	
 
 static char *cpu_vendor_names[] __initdata = {
-	"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur" };
+	"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise" };
 
 
 void __init print_cpu_info(struct cpuinfo_x86 *c)
@@ -1373,11 +1386,22 @@
 {
 	char *p = buffer;
 	int sep_bug;
+
+	/* 
+	 * Flags should be entered into the array ONLY if there is no overlap.
+	 * Else a number should be used and then overridden in the case 
+	 * statement below. --Jauder <jauderho@carumba.com>
+	 *
+	 * NOTE: bits 10, 19-22, 26-31 are reserved.
+	 *
+	 * Data courtesy of http://www.sandpile.org/arch/cpuid.htm
+	 * Thanks to the Greasel!
+	 */
 	static char *x86_cap_flags[] = {
 	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
 	        "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov",
-	        "pat", "17", "psn", "19", "20", "21", "22", "mmx",
-	        "24", "kni", "26", "27", "28", "29", "30", "31"
+	        "16", "pse36", "psn", "19", "20", "21", "22", "mmx",
+	        "24", "xmm", "26", "27", "28", "29", "30", "31"
 	};
 	struct cpuinfo_x86 *c = cpu_data;
 	int i, n;
@@ -1430,9 +1454,8 @@
 			break;
 
 		    case X86_VENDOR_INTEL:
-			x86_cap_flags[17] = "pse36";
-			x86_cap_flags[18] = "psn";
-			x86_cap_flags[24] = "osfxsr";
+			x86_cap_flags[16] = "pat";
+			x86_cap_flags[24] = "fxsr";
 			break;
 
 		    case X86_VENDOR_CENTAUR:
diff -u --recursive --new-file v2.3.38/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.3.38/linux/arch/i386/kernel/signal.c	Tue Nov 23 22:42:20 1999
+++ linux/arch/i386/kernel/signal.c	Mon Jan 10 18:15:58 2000
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/highuid.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
@@ -642,6 +643,7 @@
 				info.si_code = SI_USER;
 				info.si_pid = current->p_pptr->pid;
 				info.si_uid = current->p_pptr->uid;
+				info.si_uid16 = high2lowuid(current->p_pptr->uid);
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
diff -u --recursive --new-file v2.3.38/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.38/linux/arch/i386/kernel/smp.c	Mon Dec 20 18:48:21 1999
+++ linux/arch/i386/kernel/smp.c	Mon Jan 10 14:05:32 2000
@@ -397,9 +397,7 @@
 
 void flush_tlb_all(void)
 {
-	if (cpu_online_map ^ (1 << smp_processor_id()))
-		while (smp_call_function (flush_tlb_all_ipi,0,0,1) == -EBUSY)
-			mb();
+	smp_call_function (flush_tlb_all_ipi,0,1,1);
 
 	do_flush_tlb_all_local();
 }
@@ -438,50 +436,45 @@
  * [SUMMARY] Run a function on all other CPUs.
  * <func> The function to run. This must be fast and non-blocking.
  * <info> An arbitrary pointer to pass to the function.
- * <nonatomic> If true, we might schedule away to lock the mutex
+ * <nonatomic> currently unused.
  * <wait> If true, wait (atomically) until function has completed on other CPUs.
  * [RETURNS] 0 on success, else a negative status code. Does not return until
  * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
  */
 {
 	struct call_data_struct data;
 	int ret, cpus = smp_num_cpus-1;
-	static DECLARE_MUTEX(lock);
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
 	unsigned long timeout;
 
-	if (nonatomic)
-		down(&lock);
-	else
-		if (down_trylock(&lock))
-			return -EBUSY;
+	if(cpus == 0)
+		return 0;
 
-	call_data = &data;
 	data.func = func;
 	data.info = info;
 	atomic_set(&data.started, 0);
 	data.wait = wait;
 	if (wait)
 		atomic_set(&data.finished, 0);
-	mb();
 
+	spin_lock_bh(&lock);
+	call_data = &data;
 	/* Send a message to all other CPUs and wait for them to respond */
 	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
 	/* Wait for response */
-	timeout = jiffies + HZ;
-	while ((atomic_read(&data.started) != cpus)
-			&& time_before(jiffies, timeout))
+	/* FIXME: lock-up detection, backtrace on lock-up */
+	while(atomic_read(&data.started) != cpus)
 		barrier();
-	ret = -ETIMEDOUT;
-	if (atomic_read(&data.started) != cpus)
-		goto out;
+
 	ret = 0;
 	if (wait)
 		while (atomic_read(&data.finished) != cpus)
 			barrier();
-out:
-	call_data = NULL;
-	up(&lock);
+	spin_unlock_bh(&lock);
 	return 0;
 }
 
@@ -504,14 +497,12 @@
 
 void smp_send_stop(void)
 {
-	unsigned long flags;
+	smp_call_function(stop_this_cpu, NULL, 1, 0);
+	smp_num_cpus = 1;
 
-	__save_flags(flags);
 	__cli();
-        smp_call_function(stop_this_cpu, NULL, 1, 0);
 	disable_local_APIC();
-	__restore_flags(flags);
-
+	__sti();
 }
 
 /*
@@ -834,21 +825,18 @@
 
 void __init setup_APIC_clocks(void)
 {
-	unsigned long flags;
-
-	__save_flags(flags);
 	__cli();
 
 	calibration_result = calibrate_APIC_clock();
-
-	smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1);
-
 	/*
 	 * Now set up the timer for real.
 	 */
 	setup_APIC_timer((void *)calibration_result);
 
-	__restore_flags(flags);
+	__sti();
+
+	/* and update all other cpus */
+	smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1);
 }
 
 /*
diff -u --recursive --new-file v2.3.38/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- v2.3.38/linux/arch/i386/kernel/smpboot.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/i386/kernel/smpboot.c	Mon Jan 10 14:05:32 2000
@@ -55,7 +55,7 @@
 int skip_ioapic_setup = 0;
 
 /* Total count of live CPUs */
-int smp_num_cpus = 0;
+int smp_num_cpus = 1;
 /* Internal processor count */
 static unsigned int num_processors = 1;
 
@@ -80,8 +80,6 @@
 /* Processor that is doing the boot up */
 static unsigned int boot_cpu_id = 0;
 
-/* Tripped once we need to start cross invalidating */
-static int smp_activated = 0;
 /* Set when the idlers are all forked */
 int smp_threads_ready = 0;
 
@@ -1641,7 +1639,6 @@
 			(bogosum+2500)/500000,
 			((bogosum+2500)/5000)%100);
 		dprintk("Before bogocount - setting activated=1.\n");
-		smp_activated = 1;
 	}
 	smp_num_cpus = cpucount + 1;
 
diff -u --recursive --new-file v2.3.38/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.3.38/linux/arch/m68k/kernel/entry.S	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/kernel/entry.S	Mon Jan 10 18:15:58 2000
@@ -425,15 +425,15 @@
 	.long SYMBOL_NAME(sys_time)
 	.long SYMBOL_NAME(sys_mknod)
 	.long SYMBOL_NAME(sys_chmod)		/* 15 */
-	.long SYMBOL_NAME(sys_chown)
+	.long SYMBOL_NAME(sys_chown16)
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old break syscall holder */
 	.long SYMBOL_NAME(sys_stat)
 	.long SYMBOL_NAME(sys_lseek)
 	.long SYMBOL_NAME(sys_getpid)		/* 20 */
 	.long SYMBOL_NAME(sys_mount)
 	.long SYMBOL_NAME(sys_oldumount)
-	.long SYMBOL_NAME(sys_setuid)
-	.long SYMBOL_NAME(sys_getuid)
+	.long SYMBOL_NAME(sys_setuid16)
+	.long SYMBOL_NAME(sys_getuid16)
 	.long SYMBOL_NAME(sys_stime)		/* 25 */
 	.long SYMBOL_NAME(sys_ptrace)
 	.long SYMBOL_NAME(sys_alarm)
@@ -455,11 +455,11 @@
 	.long SYMBOL_NAME(sys_times)
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old prof syscall holder */
 	.long SYMBOL_NAME(sys_brk)		/* 45 */
-	.long SYMBOL_NAME(sys_setgid)
-	.long SYMBOL_NAME(sys_getgid)
+	.long SYMBOL_NAME(sys_setgid16)
+	.long SYMBOL_NAME(sys_getgid16)
 	.long SYMBOL_NAME(sys_signal)
-	.long SYMBOL_NAME(sys_geteuid)
-	.long SYMBOL_NAME(sys_getegid)		/* 50 */
+	.long SYMBOL_NAME(sys_geteuid16)
+	.long SYMBOL_NAME(sys_getegid16)	/* 50 */
 	.long SYMBOL_NAME(sys_acct)
 	.long SYMBOL_NAME(sys_umount)					/* recycled never used phys() */
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old lock syscall holder */
@@ -479,18 +479,18 @@
 	.long SYMBOL_NAME(sys_sigaction)
 	.long SYMBOL_NAME(sys_sgetmask)
 	.long SYMBOL_NAME(sys_ssetmask)
-	.long SYMBOL_NAME(sys_setreuid)		/* 70 */
-	.long SYMBOL_NAME(sys_setregid)
+	.long SYMBOL_NAME(sys_setreuid16)	/* 70 */
+	.long SYMBOL_NAME(sys_setregid16)
 	.long SYMBOL_NAME(sys_sigsuspend)
 	.long SYMBOL_NAME(sys_sigpending)
 	.long SYMBOL_NAME(sys_sethostname)
 	.long SYMBOL_NAME(sys_setrlimit)	/* 75 */
-	.long SYMBOL_NAME(sys_getrlimit)
+	.long SYMBOL_NAME(sys_old_getrlimit)
 	.long SYMBOL_NAME(sys_getrusage)
 	.long SYMBOL_NAME(sys_gettimeofday)
 	.long SYMBOL_NAME(sys_settimeofday)
-	.long SYMBOL_NAME(sys_getgroups)	/* 80 */
-	.long SYMBOL_NAME(sys_setgroups)
+	.long SYMBOL_NAME(sys_getgroups16)	/* 80 */
+	.long SYMBOL_NAME(sys_setgroups16)
 	.long SYMBOL_NAME(old_select)
 	.long SYMBOL_NAME(sys_symlink)
 	.long SYMBOL_NAME(sys_lstat)
@@ -504,7 +504,7 @@
 	.long SYMBOL_NAME(sys_truncate)
 	.long SYMBOL_NAME(sys_ftruncate)
 	.long SYMBOL_NAME(sys_fchmod)
-	.long SYMBOL_NAME(sys_fchown)		/* 95 */
+	.long SYMBOL_NAME(sys_fchown16)		/* 95 */
 	.long SYMBOL_NAME(sys_getpriority)
 	.long SYMBOL_NAME(sys_setpriority)
 	.long SYMBOL_NAME(sys_ni_syscall)				/* old profil syscall holder */
@@ -547,8 +547,8 @@
 	.long SYMBOL_NAME(sys_sysfs)		/* 135 */
 	.long SYMBOL_NAME(sys_personality)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* for afs_syscall */
-	.long SYMBOL_NAME(sys_setfsuid)
-	.long SYMBOL_NAME(sys_setfsgid)
+	.long SYMBOL_NAME(sys_setfsuid16)
+	.long SYMBOL_NAME(sys_setfsgid16)
 	.long SYMBOL_NAME(sys_llseek)		/* 140 */
 	.long SYMBOL_NAME(sys_getdents)
 	.long SYMBOL_NAME(sys_select)
@@ -573,14 +573,14 @@
 	.long SYMBOL_NAME(sys_sched_rr_get_interval)
 	.long SYMBOL_NAME(sys_nanosleep)
 	.long SYMBOL_NAME(sys_mremap)
-	.long SYMBOL_NAME(sys_setresuid)
-	.long SYMBOL_NAME(sys_getresuid)	/* 165 */
+	.long SYMBOL_NAME(sys_setresuid16)
+	.long SYMBOL_NAME(sys_getresuid16)	/* 165 */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* for vm86 */
 	.long SYMBOL_NAME(sys_query_module)
 	.long SYMBOL_NAME(sys_poll)
 	.long SYMBOL_NAME(sys_nfsservctl)
-	.long SYMBOL_NAME(sys_setresgid)	/* 170 */
-	.long SYMBOL_NAME(sys_getresgid)
+	.long SYMBOL_NAME(sys_setresgid16)	/* 170 */
+	.long SYMBOL_NAME(sys_getresgid16)
 	.long SYMBOL_NAME(sys_prctl)
 	.long SYMBOL_NAME(sys_rt_sigreturn)
 	.long SYMBOL_NAME(sys_rt_sigaction)
@@ -591,7 +591,7 @@
 	.long SYMBOL_NAME(sys_rt_sigsuspend)
 	.long SYMBOL_NAME(sys_pread)		/* 180 */
 	.long SYMBOL_NAME(sys_pwrite)
-	.long SYMBOL_NAME(sys_lchown);
+	.long SYMBOL_NAME(sys_lchown16);
 	.long SYMBOL_NAME(sys_getcwd)
 	.long SYMBOL_NAME(sys_capget)
 	.long SYMBOL_NAME(sys_capset)           /* 185 */
@@ -600,6 +600,29 @@
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
+	.long SYMBOL_NAME(sys_getrlimit)
+	.long SYMBOL_NAME(sys_mmap2)
+	.long SYMBOL_NAME(sys_truncate64)
+	.long SYMBOL_NAME(sys_ftruncate64)
+	.long SYMBOL_NAME(sys_chown)		/* 195 */
+	.long SYMBOL_NAME(sys_getuid)
+	.long SYMBOL_NAME(sys_getgid)
+	.long SYMBOL_NAME(sys_geteuid)
+	.long SYMBOL_NAME(sys_getegid)
+	.long SYMBOL_NAME(sys_setreuid)		/* 200 */
+	.long SYMBOL_NAME(sys_setregid)
+	.long SYMBOL_NAME(sys_getgroups)
+	.long SYMBOL_NAME(sys_setgroups)
+	.long SYMBOL_NAME(sys_fchown)
+	.long SYMBOL_NAME(sys_setresuid)	/* 205 */
+	.long SYMBOL_NAME(sys_getresuid)
+	.long SYMBOL_NAME(sys_setresgid)
+	.long SYMBOL_NAME(sys_getresgid)
+	.long SYMBOL_NAME(sys_lchown)
+	.long SYMBOL_NAME(sys_setuid)		/* 210 */
+	.long SYMBOL_NAME(sys_setgid)
+	.long SYMBOL_NAME(sys_setfsuid)
+	.long SYMBOL_NAME(sys_setfsgid)
 
 	.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
 		.long SYMBOL_NAME(sys_ni_syscall)
diff -u --recursive --new-file v2.3.38/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.3.38/linux/arch/m68k/kernel/signal.c	Tue Nov 23 22:42:20 1999
+++ linux/arch/m68k/kernel/signal.c	Mon Jan 10 18:15:58 2000
@@ -37,6 +37,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/highuid.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -1048,6 +1049,7 @@
 				info.si_code = SI_USER;
 				info.si_pid = current->p_pptr->pid;
 				info.si_uid = current->p_pptr->uid;
+				info.si_uid16 = high2lowuid(current->p_pptr->uid);
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.3.38/linux/arch/ppc/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/ppc/Makefile	Sat Jan  8 12:59:39 2000
@@ -155,9 +155,6 @@
 walnut_config: clean_config
 	ln -s configs/walnut_defconfig arch/ppc/defconfig
 
-tags:
-	etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
-
 archclean:
 	rm -f arch/ppc/kernel/{mk_defs,ppc_defs.h,find_name,checks}
 	@$(MAKECOFFBOOT) clean
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- v2.3.38/linux/arch/ppc/coffboot/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/ppc/coffboot/Makefile	Mon Jan 10 18:25:32 2000
@@ -39,11 +39,13 @@
 hack-coff: hack-coff.c
 	$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
 
-znetboot: vmlinux.coff zImage
+znetboot: vmlinux.coff vmlinux.elf zImage
 	cp vmlinux.coff $(TFTPIMAGE)
+	cp vmlinux.elf $(TFTPIMAGE).elf
 
 znetboot.initrd: vmlinux.coff.initrd
 	cp vmlinux.coff.initrd $(TFTPIMAGE)
+	cp vmlinux.elf.initrd $(TFTPIMAGE).elf
 
 floppy: zImage
 #	mount -t hfs /dev/fd0 /mnt
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/coffboot/chrpmain.c linux/arch/ppc/coffboot/chrpmain.c
--- v2.3.38/linux/arch/ppc/coffboot/chrpmain.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/coffboot/chrpmain.c	Sat Jan  8 12:59:39 2000
@@ -10,7 +10,6 @@
 #include "zlib.h"
 #include <asm/bootinfo.h>
 #include <asm/processor.h>
-#define __KERNEL__
 #include <asm/page.h>
 
 extern void *finddevice(const char *);
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/coffboot/coffmain.c linux/arch/ppc/coffboot/coffmain.c
--- v2.3.38/linux/arch/ppc/coffboot/coffmain.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/coffboot/coffmain.c	Sat Jan  8 12:59:39 2000
@@ -10,7 +10,6 @@
 #include "zlib.h"
 #include <asm/bootinfo.h>
 #include <asm/processor.h>
-#define __KERNEL__
 #include <asm/page.h>
 
 extern void *finddevice(const char *);
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.38/linux/arch/ppc/config.in	Wed Dec 29 13:13:12 1999
+++ linux/arch/ppc/config.in	Mon Jan 10 18:25:06 2000
@@ -116,7 +116,7 @@
 
 source drivers/parport/Config.in
 
-if [ "$CONFIG_8xx" != "y" ]; then
+if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then
   bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
   bool 'Support for frame buffer devices' CONFIG_FB
   if [ "$CONFIG_FB" = "y" ]; then
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig
--- v2.3.38/linux/arch/ppc/configs/gemini_defconfig	Tue Dec 14 01:27:23 1999
+++ linux/arch/ppc/configs/gemini_defconfig	Mon Jan 10 18:25:32 2000
@@ -46,6 +46,7 @@
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
+# CONFIG_PCI_NAMES is not set
 
 #
 # PCMCIA/CardBus support
@@ -161,6 +162,7 @@
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
+# CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -243,7 +245,6 @@
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_YELLOWFIN is not set
 # CONFIG_RTL8139 is not set
 # CONFIG_DM9102 is not set
 # CONFIG_AT1700 is not set
@@ -251,6 +252,13 @@
 # CONFIG_NET_ISA is not set
 # CONFIG_NET_EISA is not set
 # CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PPP is not set
@@ -310,10 +318,20 @@
 CONFIG_UNIX98_PTY_COUNT=256
 
 #
+# 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
 
 #
@@ -327,11 +345,6 @@
 # Video For Linux
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Joystick support
-#
-# CONFIG_JOYSTICK is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -341,9 +354,10 @@
 #
 # CONFIG_FTAPE is not set
 # CONFIG_DRM is not set
+# CONFIG_AGP is not set
 
 #
-# Support for USB
+# USB support
 #
 # CONFIG_USB is not set
 
@@ -358,9 +372,9 @@
 # CONFIG_BFS_FS is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -370,16 +384,17 @@
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
-# CONFIG_NFS_FS is not set
+CONFIG_NFS_FS=y
 # CONFIG_NFSD is not set
-# CONFIG_SUNRPC is not set
-# CONFIG_LOCKD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 
@@ -403,4 +418,4 @@
 #
 # CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_KGDB is not set
-# CONFIG_XMON is not set
+CONFIG_XMON=y
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/configs/oak_defconfig linux/arch/ppc/configs/oak_defconfig
--- v2.3.38/linux/arch/ppc/configs/oak_defconfig	Tue Dec 14 01:27:23 1999
+++ linux/arch/ppc/configs/oak_defconfig	Mon Jan 10 18:25:06 2000
@@ -3,36 +3,43 @@
 #
 
 #
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
 # Platform support
 #
 CONFIG_PPC=y
-CONFIG_4xx=y
 # CONFIG_6xx is not set
+CONFIG_4xx=y
 # CONFIG_PPC64 is not set
 # CONFIG_82xx is not set
 # CONFIG_8xx is not set
-CONFIG_403=y
-# CONFIG_405 is not set
 CONFIG_OAK=y
+# CONFIG_WALNUT is not set
+# CONFIG_PCI is not set
 # CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 # CONFIG_MATH_EMULATION is not set
 
 #
-# General setup
+# Loadable module support
 #
-# CONFIG_EXPERIMENTAL is not set
 CONFIG_MODULES=y
 # CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
-# CONFIG_PCI is not set
+
+#
+# General setup
+#
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=y
+# CONFIG_BINFMT_MISC is not set
 
 #
 # PCMCIA/CardBus support
@@ -66,7 +73,6 @@
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
 # CONFIG_BLK_DEV_HD_ONLY is not set
-# CONFIG_BLK_CPQ_DA is not set
 
 #
 # Additional Block Devices
@@ -77,7 +83,6 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
@@ -108,12 +113,29 @@
 # (it is safe to leave these untouched)
 #
 # CONFIG_SKB_LARGE 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_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC 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
 
 #
 # SCSI support
@@ -140,15 +162,27 @@
 # CONFIG_MACE is not set
 # CONFIG_BMAC is not set
 # CONFIG_NCR885E is not set
+CONFIG_OAKNET=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_RTL8139 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
 # CONFIG_NET_ISA is not set
 # CONFIG_NET_EISA is not set
 # CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC 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
 
@@ -162,6 +196,8 @@
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
 
 #
 # Wan interfaces
@@ -208,6 +244,10 @@
 # CONFIG_BUSMOUSE is not set
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
@@ -229,9 +269,10 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
 
 #
-# USB drivers - not for the faint of heart
+# Support for USB
 #
 # CONFIG_USB is not set
 
@@ -239,13 +280,16 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS 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_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_UDF_FS is not set
@@ -253,7 +297,8 @@
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-CONFIG_ROMFS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
@@ -274,8 +319,8 @@
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MAC_PARTITION=y
-CONFIG_MSDOS_PARTITION=y
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_NLS is not set
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/configs/walnut_defconfig linux/arch/ppc/configs/walnut_defconfig
--- v2.3.38/linux/arch/ppc/configs/walnut_defconfig	Tue Dec 14 01:27:23 1999
+++ linux/arch/ppc/configs/walnut_defconfig	Mon Jan 10 18:25:06 2000
@@ -3,36 +3,43 @@
 #
 
 #
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
 # Platform support
 #
 CONFIG_PPC=y
-CONFIG_4xx=y
 # CONFIG_6xx is not set
+CONFIG_4xx=y
 # CONFIG_PPC64 is not set
 # CONFIG_82xx is not set
 # CONFIG_8xx is not set
-CONFIG_403=y
-# CONFIG_405 is not set
-CONFIG_OAK=y
+# CONFIG_OAK is not set
+CONFIG_WALNUT=y
+CONFIG_PCI=y
 # CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 # CONFIG_MATH_EMULATION is not set
 
 #
-# General setup
+# Loadable module support
 #
-# CONFIG_EXPERIMENTAL is not set
 CONFIG_MODULES=y
 # CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
-CONFIG_PCI=y
+
+#
+# General setup
+#
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=y
+# CONFIG_BINFMT_MISC is not set
 
 #
 # PCMCIA/CardBus support
@@ -66,7 +73,6 @@
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
 # CONFIG_BLK_DEV_HD_ONLY is not set
-# CONFIG_BLK_CPQ_DA is not set
 
 #
 # Additional Block Devices
@@ -77,7 +83,6 @@
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_IDE_MODES is not set
@@ -108,12 +113,29 @@
 # (it is safe to leave these untouched)
 #
 # CONFIG_SKB_LARGE 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_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC 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
 
 #
 # SCSI support
@@ -140,15 +162,27 @@
 # CONFIG_MACE is not set
 # CONFIG_BMAC is not set
 # CONFIG_NCR885E is not set
+# CONFIG_OAKNET is not set
 # 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_RTL8139 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_AT1700 is not set
 # CONFIG_DEPCA is not set
 # CONFIG_NET_ISA is not set
 # CONFIG_NET_EISA is not set
 # CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC 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
 
@@ -162,6 +196,8 @@
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
 
 #
 # Wan interfaces
@@ -208,6 +244,10 @@
 # CONFIG_BUSMOUSE is not set
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
@@ -229,9 +269,10 @@
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_DRM is not set
 
 #
-# USB drivers - not for the faint of heart
+# Support for USB
 #
 # CONFIG_USB is not set
 
@@ -239,13 +280,16 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_ADFS_FS 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_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_UDF_FS is not set
@@ -253,7 +297,8 @@
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-CONFIG_ROMFS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.3.38/linux/arch/ppc/kernel/Makefile	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/Makefile	Mon Jan 10 18:25:05 2000
@@ -57,8 +57,11 @@
 O_OBJS += smp.o
 endif
 
-ifeq ($(CONFIG_OAK),y)
-  O_OBJS += oak_setup.o
+ifeq ($(CONFIG_4xx),y)
+  O_OBJS += ppc4xx_pic.o
+  ifeq ($(CONFIG_OAK),y)
+    O_OBJS += oak_setup.o
+  endif
 endif
 
 ifeq ($(CONFIG_8xx),y)
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- v2.3.38/linux/arch/ppc/kernel/entry.S	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/entry.S	Mon Jan 10 18:25:05 2000
@@ -291,11 +291,13 @@
 ret_from_syscall:
 	.globl	ret_from_except
 ret_from_except:
-0:	mfmsr	r30		/* Disable interrupts */
-	rlwinm	r30,r30,0,17,15	/* clear MSR_EE */
-	SYNC			/* Some chip revs need this... */
-	mtmsr	r30
-	SYNC
+0:	/* disable interrupts */	
+	lis	r30,int_control@h
+	ori	r30,r30,int_control@l
+	lwz	r30,0(r30)
+	mtlr	r30
+	blrl
+	
 	lwz	r5,_MSR(r1)
 	andi.	r5,r5,MSR_EE
 	beq	2f
@@ -317,9 +319,13 @@
 	bl	do_bottom_half
 	.globl	do_bottom_half_ret
 do_bottom_half_ret:
-2:	SYNC
-	mtmsr	r30		/* disable interrupts again */
-	SYNC
+2:	/* disable interrupts */	
+	lis	r30,int_control@h
+	ori	r30,r30,int_control@l
+	lwz	r30,0(r30)
+	mtlr	r30
+	blrl
+	
 	lwz	r3,_MSR(r1)	/* Returning to user mode? */
 	andi.	r3,r3,MSR_PR
 	beq+	10f		/* if so, check need_resched and signals */
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/gemini_pci.c linux/arch/ppc/kernel/gemini_pci.c
--- v2.3.38/linux/arch/ppc/kernel/gemini_pci.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/gemini_pci.c	Mon Jan 10 18:25:05 2000
@@ -229,13 +229,11 @@
 {
 	struct pci_dev *dev;
 
-	if (!bus->devices && !bus->children)
-		return;
-
 	io_base = ALIGN(io_base, 4*KB);
 	mem_base = ALIGN(mem_base, 4*KB);
 
-	for( dev = bus->devices; dev; dev = dev->sibling ) {
+	pci_for_each_dev(dev)
+	{
 		if (((dev->class >> 16) != PCI_BASE_CLASS_BRIDGE) ||
 		    ((dev->class >> 8) == PCI_CLASS_BRIDGE_OTHER))
 			layout_dev( dev );
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.3.38/linux/arch/ppc/kernel/gemini_setup.c	Wed Dec 29 13:13:12 1999
+++ linux/arch/ppc/kernel/gemini_setup.c	Mon Jan 10 18:25:32 2000
@@ -330,7 +330,7 @@
 	int i;
 
 	/* gemini has no 8259 */
-	open_pic.irq_offset = 0;
+	open_pic_irq_offset = 0;
 	for( i=0; i < NR_IRQS; i++ ) 
 		irq_desc[i].handler = &open_pic;
 	openpic_init(1);
@@ -515,7 +515,7 @@
 	 * We do it this way since our irq_desc[irq].handler can change
 	 * with RTL and no longer be open_pic -- Cort
 	 */
-	if ( irq >= open_pic.irq_offset)
+	if ( irq >= open_pic_irq_offset)
 		openpic_eoi( smp_processor_id() );
 }
 
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.38/linux/arch/ppc/kernel/head.S	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/head.S	Mon Jan 10 18:25:05 2000
@@ -287,7 +287,8 @@
 	stw	r2,GPR2(r21);	\
 	stw	r1,0(r21);	\
 	tovirt(r1,r21);			/* set new kernel sp */	\
-	SAVE_4GPRS(3, r21);
+	SAVE_4GPRS(3, r21);	\
+	SAVE_GPR(7, r21);
 /*
  * Note: code which follows this uses cr0.eq (set if from kernel),
  * r21, r22 (SRR0), and r23 (SRR1).
@@ -374,7 +375,7 @@
 	.globl do_IRQ_intercept
 do_IRQ_intercept:
 	.long	do_IRQ;
-	.long	ret_from_except
+	.long	ret_from_int
 #else
 	bl	apus_interrupt_entry
 #endif /* CONFIG_APUS */
@@ -424,7 +425,7 @@
 	.globl timer_interrupt_intercept
 timer_interrupt_intercept:
 	.long	timer_interrupt
-	.long	ret_from_except
+	.long	ret_from_int
 
 	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
 	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
@@ -674,7 +675,6 @@
 transfer_to_handler:
 	stw	r22,_NIP(r21)
 	stw	r23,_MSR(r21)
-	SAVE_GPR(7, r21)
 	SAVE_4GPRS(8, r21)
 	SAVE_8GPRS(12, r21)
 	SAVE_8GPRS(24, r21)
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/head_4xx.S linux/arch/ppc/kernel/head_4xx.S
--- v2.3.38/linux/arch/ppc/kernel/head_4xx.S	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/head_4xx.S	Mon Jan 10 18:25:32 2000
@@ -27,10 +27,8 @@
 #include <linux/config.h>
 
 #include <asm/processor.h>
-#include <asm/4xx.h>
-#include <asm/403gcx.h>
-#include <asm/405gp.h>
 #include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/mmu.h>
 
 #include "ppc_asm.h"
@@ -58,7 +56,7 @@
 ### execution begins here, the following registers contain valid, yet
 ### optional, information:
 ###
-###   r3 - ???
+###   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
 ###   r4 - Starting address of the init RAM disk
 ###   r5 - Ending address of the init RAM disk
 ###   r6 - Start of kernel command line string (e.g. "mem=96m")
@@ -80,17 +78,55 @@
 
 	li	r24,0
 
-	## Establish exception vector base
+	## We should still be executing code at physical address 0x0000xxxx
+	## at this point. However, start_here is at virtual address
+	## 0xC000xxxx. So, set up a TLB mapping to cover this once
+	## translation is enabled.
+
+	lis	r3,KERNELBASE@h		# Load the kernel virtual address
+	addis	r3,r3,KERNELBASE@l
+	tophys(r4,r3)			# Load the kernel physical address
+
+	## Save the existing PID and load the kernel PID.
+		
+	mfspr	r7,SPRN_PID		# Save the old PID
+	li	r0,0
+	mtspr	SPRN_PID,r0		# Load the kernel PID
+
+	## Configure and load entry into TLB slot 0.
 	
-	lis	r0,KERNELBASE@h
-	mtspr	SPRN_EVPR,r0
+	clrrwi	r4,r4,10		# Mask off the real page number
+
+	## XXX - Temporarily set the TLB_I bit because of cache issues that
+	##       seem to foul-up the exception handling code.
 
-	## Jump to the main PowerPC kernel start-up code
+	ori	r4,r4,(TLB_WR | TLB_EX | TLB_I)	# Set the write and execute bits
 	
-1:	lis	r7,start_here@ha
-	addi	r7,r7,start_here@l
-	mtlr	r7
-	blr
+	clrrwi	r3,r3,10		# Mask off the effective page number
+	ori	r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
+
+	tlbwe	r4,r0,TLB_DATA		# Load the data portion of the entry
+	tlbwe	r3,r0,TLB_TAG		# Load the tag portion of the entry
+	isync
+	
+	mtspr	SPRN_PID,r7		# Restore the existing PID
+	
+	## Establish the exception vector base
+	
+	lis	r4,KERNELBASE@h		# EVPR only uses the high 16-bits
+	tophys(r0,r4)			# Use the physical address
+	mtspr	SPRN_EVPR,r0
+
+	## Enable the MMU and jump to the main PowerPC kernel start-up code
+
+	mfmsr	r0			# Get the machine state register
+	ori	r0,r0,(MSR_DR | MSR_IR)	# Enable data and instr. translation
+	mtspr	SPRN_SRR1,r0		# Set up the new machine state register
+	lis	r0,start_here@h		
+	ori	r0,r0,start_here@l	
+	mtspr	SPRN_SRR0,r0		# Set up the new instruction pointer
+	rfi				# Jump to start_here w/ translation on
+
 
 ###
 ### Exception vector entry code. This code runs with address translation
@@ -129,7 +165,8 @@
 	stw	r2,GPR2(r21);		/* Save r2 on the stack		   */\
 	stw	r1,0(r21);						     \
 	tovirt(r1,r21);			/* Set-up new kernel stack pointer */\
-	SAVE_4GPRS(3, r21);		/* Save r3 through r6 on the stack */
+	SAVE_4GPRS(3, r21);		/* Save r3 through r6 on the stack */\
+	SAVE_GPR(7, r21);		/* Save r7 on the stack		   */
 
 	## Common exception code for standard (non-critical) exceptions.
 
@@ -166,7 +203,7 @@
 	START_EXCEPTION(n, label);					     \
 	STND_EXCEPTION_PROLOG;						     \
 	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \
-	li	r0,STND_EXC;						     \
+	li	r7,STND_EXC;						     \
 	li	r20,MSR_KERNEL;						     \
 	FINISH_EXCEPTION(func)
 
@@ -175,23 +212,10 @@
 	START_EXCEPTION(n, label);					     \
 	CRIT_EXCEPTION_PROLOG;						     \
 	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \
-	li	r0,CRIT_EXC;						     \
+	li	r7,CRIT_EXC;						     \
 	li	r20,MSR_KERNEL;						     \
 	FINISH_EXCEPTION(func)
 
-
-#define	INTR_EXCEPTION(n, label, func)					     \
-	START_EXCEPTION(n, label);					     \
-	STND_EXCEPTION_PROLOG;						     \
-	addi	r3,r1,STACK_FRAME_OVERHEAD;				     \
-	li	r0,STND_EXC;						     \
-	li	r20,MSR_KERNEL;						     \
-	li	r4,0;							     \
-	bl	transfer_to_handler;					     \
-_GLOBAL(do_IRQ_intercept);						     \
-	.long	func;							     \
-	.long	ret_from_except
-
 	
 ###
 ### Exception vectors.
@@ -214,7 +238,7 @@
 	mfspr	r4,SPRN_DEAR		# Grab the DEAR, save it, pass as arg2
 	stw	r4,_DEAR(r21)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r0,STND_EXC		# This is a standard exception
+	li	r7,STND_EXC		# This is a standard exception
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		# Copy EE bit from the saved MSR
 	FINISH_EXCEPTION(do_page_fault)	# do_page_fault(regs, ESR, DEAR)
@@ -226,15 +250,24 @@
 	mr	r4,r22			# Pass SRR0 as arg2
 	mr	r5,r23			# Pass SRR1 as arg3
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r0,STND_EXC		# This is a standard exception
+	li	r7,STND_EXC		# This is a standard exception
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		# Copy EE bit from the saved MSR
 	FINISH_EXCEPTION(do_page_fault)	# do_page_fault(regs, SRR0, SRR1)
 	
 ### 0x0500 - External Interrupt Exception
 
-	INTR_EXCEPTION(0x0500,	HardwareInterrupt,	do_IRQ)
-	
+	START_EXCEPTION(0x0500, HardwareInterrupt)
+	STND_EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r7,STND_EXC
+	li	r20,MSR_KERNEL
+	li	r4,0
+	bl	transfer_to_handler
+_GLOBAL(do_IRQ_intercept)
+	.long	do_IRQ
+	.long	ret_from_except
+
 ### 0x0600 - Alignment Exception
 	
 	START_EXCEPTION(0x0600, Alignment)
@@ -242,7 +275,7 @@
 	mfspr	r4,SPRN_DEAR		# Grab the DEAR and save it
 	stw	r4,_DEAR(r21)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r0,STND_EXC		# This is a standard exception
+	li	r7,STND_EXC		# This is a standard exception
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		# Copy EE bit from the saved MSR
 	FINISH_EXCEPTION(AlignmentException)
@@ -252,7 +285,7 @@
 	START_EXCEPTION(0x0700,	ProgramCheck)
 	STND_EXCEPTION_PROLOG
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r0,STND_EXC		# This is a standard exception
+	li	r7,STND_EXC		# This is a standard exception
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		# Copy EE bit from the saved MSR
 	FINISH_EXCEPTION(ProgramCheckException)
@@ -266,7 +299,7 @@
 	START_EXCEPTION(0x0C00,	SystemCall)
 	STND_EXCEPTION_PROLOG
 	stw	r3,ORIG_GPR3(r21)
-	li	r0,STND_EXC		# This is a standard exception
+	li	r7,STND_EXC		# This is a standard exception
 	li	r20,MSR_KERNEL
 	rlwimi	r20,r23,0,16,16		# Copy EE bit from the saved MSR
 	FINISH_EXCEPTION(DoSyscall)
@@ -275,11 +308,21 @@
 	STND_EXCEPTION(0x0E00,	Trap_0E,		UnknownException)
 	STND_EXCEPTION(0x0F00,	Trap_0F,		UnknownException)
 
-#if 0
 ### 0x1000 - Programmable Interval Timer (PIT) Exception
 
-	STND_EXCEPTION(0x1000,	PITException,		UnknownException)
+	START_EXCEPTION(0x1000,	Decrementer)
+	STND_EXCEPTION_PROLOG
+	lis	r0,TSR_PIS@h		# Set-up the PIT exception mask
+	mtspr	SPRN_TSR,r0		# Clear the PIT exception
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	li	r7,STND_EXC		# This is a standard exception
+	li	r20,MSR_KERNEL
+	bl	transfer_to_handler
+_GLOBAL(timer_interrupt_intercept)
+	.long	timer_interrupt
+	.long	ret_from_except
 
+#if 0
 ### 0x1010 - Fixed Interval Timer (FIT) Exception
 	
 	STND_EXCEPTION(0x1010,	FITException,		UnknownException)
@@ -294,7 +337,7 @@
 	START_EXCEPTION(0x1100,	DTLBMiss)
 	STND_EXCEPTION_PROLOG
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r0,STND_EXC
+	li	r7,STND_EXC
 	li	r20,MSR_KERNEL
 	FINISH_EXCEPTION(UnknownException)
 
@@ -303,7 +346,7 @@
 	START_EXCEPTION(0x1200,	ITLBMiss)
 	STND_EXCEPTION_PROLOG
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	li	r0,STND_EXC
+	li	r7,STND_EXC
 	li	r20,MSR_KERNEL
 	FINISH_EXCEPTION(UnknownException)	
 
@@ -341,7 +384,6 @@
 _GLOBAL(transfer_to_handler)
 	stw	r22,_NIP(r21)		# Save the faulting IP on the stack
 	stw	r23,_MSR(r21)		# Save the exception MSR on the stack
-	SAVE_GPR(7, r21)		# Save r7 on the stack
 	SAVE_4GPRS(8, r21)		# Save r8 through r11 on the stack
 	SAVE_8GPRS(12, r21)		# Save r12 through r19 on the stack
 	SAVE_8GPRS(24, r21)		# Save r24 through r31 on the stack
@@ -367,7 +409,7 @@
 	bgt-	stack_ovf		# If r2 < r1 < r2 + TASK_STRUCT_SIZE
 	lwz	r24,0(r23)		# Virtual address of the handler
 	lwz	r23,4(r23)		# Handler return pointer
-	cmpwi	cr0,r0,STND_EXC		# What type of exception is this?
+	cmpwi	cr0,r7,STND_EXC		# What type of exception is this?
 	bne	3f			# It is a critical exception...
 
 	## Standard exception jump path
@@ -432,67 +474,10 @@
 	
 _GLOBAL(abort)
 	mfspr	r13,SPRN_DBCR
-	ori	r13,r13,DBCR_RST(SYSTEM)@h
+	oris	r13,r13,DBCR_RST(SYSTEM)@h
 	mtspr	SPRN_DBCR,r13
 
-	
-###
-### This code is jumped-to from the startup code. It copies the kernel
-### image from wherever it happens to be currently running at in physical
-### address space to physical address 0.
-###
-### In general, for a running Linux/PPC system:
-###   Kernel Physical Address (KPA) = 0x00000000
-###   Kernel Virtual Address (KVA)  = 0xC0000000
-###
- 
-#if 0
-relocate_kernel:
-	lis	r9,0x426f		/* if booted from BootX, don't */
-	addi	r9,r9,0x6f58		/* translate source addr */
-	cmpw	r31,r9			/* (we have to on chrp) */
-	beq	7f
-	rlwinm	r4,r4,0,8,31		/* translate source address */
-	add	r4,r4,r3		/* to region mapped with BATs */
-7:	addis	r9,r26,klimit@ha	/* fetch klimit */
-	lwz	r25,klimit@l(r9)
-	addis	r25,r25,-KERNELBASE@h
-	li	r6,0			/* Destination offset */
-	li	r5,0x4000		/* # bytes of memory to copy */
-	bl	copy_and_flush		/* copy the first 0x4000 bytes */
-	addi	r0,r3,4f@l		/* jump to the address of 4f */
-	mtctr	r0			/* in copy and do the rest. */
-	bctr				/* jump to the copy */
-4:	mr	r5,r25
-	bl	copy_and_flush		/* copy the rest */
-	b	turn_on_mmu
-
-/*
- * Copy routine used to copy the kernel to start at physical address 0
- * and flush and invalidate the caches as needed.
- * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
- * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
- */
-copy_and_flush:
-	addi	r5,r5,-4
-	addi	r6,r6,-4
-4:	li	r0,8
-	mtctr	r0
-3:	addi	r6,r6,4			/* copy a cache line */
-	lwzx	r0,r6,r4
-	stwx	r0,r6,r3
-	bdnz	3b
-	dcbst	r6,r3			/* write it to memory */
-	sync
-	icbi	r6,r3			/* flush the icache line */
-	cmplw	0,r6,r5
-	blt	4b
-	isync
-	addi	r5,r5,4
-	addi	r6,r6,4
-	blr
-#endif
-	
+
 ### 
 ### This is where the main kernel code starts.
 ### 
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S
--- v2.3.38/linux/arch/ppc/kernel/head_8xx.S	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/head_8xx.S	Mon Jan 10 18:25:32 2000
@@ -197,7 +197,8 @@
 	stw	r2,GPR2(r21);	\
 	stw	r1,0(r21);	\
 	tovirt(r1,r21);			/* set new kernel sp */	\
-	SAVE_4GPRS(3, r21);
+	SAVE_4GPRS(3, r21);	\
+	SAVE_GPR(7, r21);
 /*
  * Note: code which follows this uses cr0.eq (set if from kernel),
  * r21, r22 (SRR0), and r23 (SRR1).
@@ -591,7 +592,6 @@
 	lis	r22,MSR_POW@h
 	andc	r23,r23,r22
 	stw	r23,_MSR(r21)
-	SAVE_GPR(7, r21)
 	SAVE_4GPRS(8, r21)
 	SAVE_8GPRS(12, r21)
 	SAVE_8GPRS(24, r21)
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.38/linux/arch/ppc/kernel/irq.c	Wed Dec 29 13:13:12 1999
+++ linux/arch/ppc/kernel/irq.c	Mon Jan 10 18:25:32 2000
@@ -294,11 +294,10 @@
 	}
 }
 
-asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
+asmlinkage int do_IRQ(struct pt_regs *regs, int isfake)
 {
 	int cpu = smp_processor_id();
 	int irq;
-
         hardirq_enter( cpu );
 
 	/* every arch is required to have a get_irq -- Cort */
@@ -320,9 +319,8 @@
 
  out:	
         hardirq_exit( cpu );
+	return 1; /* lets ret_from_int know we can do checks */
 }
-
-
 
 unsigned long probe_irq_on (void)
 {
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/oak_setup.c linux/arch/ppc/kernel/oak_setup.c
--- v2.3.38/linux/arch/ppc/kernel/oak_setup.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/oak_setup.c	Mon Jan 10 18:25:32 2000
@@ -7,26 +7,74 @@
  *    Description:
  *      Architecture- / platform-specific boot-time initialization code for
  *      the IBM PowerPC 403GCX "Oak" evaluation board. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek
- *      <dmalek@jlc.net>.
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
  *
  */
 
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/interrupt.h>
+#include <linux/param.h>
 #include <linux/string.h>
 
+#include <asm/processor.h>
+#include <asm/board.h>
 #include <asm/machdep.h>
 #include <asm/page.h>
 
+#include "local_irq.h"
+#include "ppc4xx_pic.h"
+#include "time.h"
 #include "oak_setup.h"
 
+/* Function Prototypes */
 
+extern void abort(void);
+
+/* Global Variables */
+
+unsigned char __res[sizeof(bd_t)];
+
+
+/*
+ * void __init oak_init()
+ *
+ * Description:
+ *   This routine...
+ *
+ * Input(s):
+ *   r3 - Optional pointer to a board information structure.
+ *   r4 - Optional pointer to the physical starting address of the init RAM
+ *        disk.
+ *   r5 - Optional pointer to the physical ending address of the init RAM
+ *        disk.
+ *   r6 - Optional pointer to the physical starting address of any kernel
+ *        command-line parameters.
+ *   r7 - Optional pointer to the physical ending address of any kernel
+ *        command-line parameters.
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
 void __init
 oak_init(unsigned long r3, unsigned long r4, unsigned long r5, 
 	 unsigned long r6, unsigned long r7)
 {
-#if 0
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3) {
+		memcpy((void *)__res, (void *)(r3 + KERNELBASE), sizeof(bd_t));
+	}
+
 #if defined(CONFIG_BLK_DEV_INITRD)
 	/*
 	 * If the init RAM disk has been configured in, and there's a valid
@@ -44,24 +92,25 @@
  		*(char *)(r7 + KERNELBASE) = 0;
 		strcpy(cmd_line, (char *)(r6 + KERNELBASE));
 	}
-#endif /* 0 */
+
+	/* Initialize machine-dependency vectors */
 
 	ppc_md.setup_arch	 = oak_setup_arch;
-	ppc_md.setup_residual	 = NULL;
+	ppc_md.setup_residual	 = oak_setup_residual;
 	ppc_md.get_cpuinfo	 = NULL;
 	ppc_md.irq_cannonicalize = NULL;
-	ppc_md.init_IRQ		 = NULL;
-	ppc_md.get_irq		 = NULL;
+	ppc_md.init_IRQ		 = oak_init_IRQ;
+	ppc_md.get_irq		 = oak_get_irq;
 	ppc_md.init		 = NULL;
 
-	ppc_md.restart		 = NULL;
-	ppc_md.power_off	 = NULL;
-	ppc_md.halt		 = NULL;
-
-	ppc_md.time_init	 = NULL;
-	ppc_md.set_rtc_time	 = NULL;
-	ppc_md.get_rtc_time	 = NULL;
-	ppc_md.calibrate_decr	 = NULL;
+	ppc_md.restart		 = oak_restart;
+	ppc_md.power_off	 = oak_power_off;
+	ppc_md.halt		 = oak_halt;
+
+	ppc_md.time_init	 = oak_time_init;
+	ppc_md.set_rtc_time	 = oak_set_rtc_time;
+	ppc_md.get_rtc_time	 = oak_get_rtc_time;
+	ppc_md.calibrate_decr	 = oak_calibrate_decr;
 
 	ppc_md.kbd_setkeycode    = NULL;
 	ppc_md.kbd_getkeycode    = NULL;
@@ -77,8 +126,168 @@
 	return;
 }
 
+/*
+ * Document me.
+ */
 void __init
 oak_setup_arch(void)
 {
+	/* XXX - Implement me */
+}
+
+/*
+ * int oak_setup_residual()
+ *
+ * Description:
+ *   This routine pretty-prints the platform's internal CPU and bus clock
+ *   frequencies into the buffer for usage in /proc/cpuinfo.
+ *
+ * Input(s):
+ *  *buffer - Buffer into which CPU and bus clock frequencies are to be
+ *            printed.
+ *
+ * Output(s):
+ *  *buffer - Buffer with the CPU and bus clock frequencies.
+ *
+ * Returns:
+ *   The number of bytes copied into 'buffer' if OK, otherwise zero or less
+ *   on error.
+ */
+int
+oak_setup_residual(char *buffer)
+{
+	int len = 0;
+	bd_t *bp = (bd_t *)__res;
+
+	len += sprintf(len + buffer,
+		       "clock\t\t: %dMHz\n"
+		       "bus clock\t\t: %dMHz\n",
+		       bp->bi_intfreq / 1000000,
+		       bp->bi_busfreq / 1000000);
+
+	return (len);
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_init_IRQ(void)
+{
+	int i;
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc[i].handler = ppc4xx_pic;
+	}
+
+	return;
+}
+
+/*
+ * Document me.
+ */
+int
+oak_get_irq(struct pt_regs *regs)
+{
+	return (ppc4xx_pic_get_irq(regs));
+}
+
+/*
+ * Document me.
+ */
+void
+oak_restart(char *cmd)
+{
+	abort();
+}
+
+/*
+ * Document me.
+ */
+void
+oak_power_off(void)
+{
+	oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void
+oak_halt(void)
+{
+	oak_restart(NULL);
+}
+
+/*
+ * Document me.
+ */
+void __init
+oak_time_init(void)
+{
+	/* XXX - Implement me */
+}
+
+/*
+ * Document me.
+ */
+int __init
+oak_set_rtc_time(unsigned long time)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * Document me.
+ */
+unsigned long __init
+oak_get_rtc_time(void)
+{
+	/* XXX - Implement me */
+
+	return (0);
+}
+
+/*
+ * void __init oak_calibrate_decr()
+ *
+ * Description:
+ *   This routine retrieves the internal processor frequency from the board
+ *   information structure, sets up the kernel timer decrementer based on
+ *   that value, enables the 403 programmable interval timer (PIT) and sets
+ *   it up for auto-reload.
+ *
+ * Input(s):
+ *   N/A
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+void __init
+oak_calibrate_decr(void)
+{
+	unsigned int freq;
+	bd_t *bip = (bd_t *)__res;
+
+	freq = bip->bi_intfreq;
+
+	decrementer_count = freq / HZ;
+	count_period_num = 1;
+	count_period_den = freq;
+
+	/* Enable the PIT and set auto-reload of its value */
+
+	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+	/* Clear any pending timer interrupts */
 
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
 }
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/oak_setup.h linux/arch/ppc/kernel/oak_setup.h
--- v2.3.38/linux/arch/ppc/kernel/oak_setup.h	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/oak_setup.h	Mon Jan 10 18:25:32 2000
@@ -15,14 +15,32 @@
 #ifndef	__OAK_SETUP_H__
 #define	__OAK_SETUP_H__
 
+#include <asm/ptrace.h>
+#include <asm/board.h>
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-extern void	 oak_init(unsigned long r3,
-			  unsigned long ird_start, unsigned long ird_end,
-			  unsigned long cline_start, unsigned long cline_end);
-extern void	 oak_setup_arch(void);
+extern unsigned char	 __res[sizeof(bd_t)];
+
+extern void		 oak_init(unsigned long r3,
+				  unsigned long ird_start,
+				  unsigned long ird_end,
+				  unsigned long cline_start,
+				  unsigned long cline_end);
+extern void		 oak_setup_arch(void);
+extern int		 oak_setup_residual(char *buffer);
+extern void		 oak_init_IRQ(void);
+extern int		 oak_get_irq(struct pt_regs *regs);
+extern void		 oak_restart(char *cmd);
+extern void		 oak_power_off(void);
+extern void		 oak_halt(void);
+extern void		 oak_time_init(void);
+extern int		 oak_set_rtc_time(unsigned long now);
+extern unsigned long	 oak_get_rtc_time(void);
+extern void		 oak_calibrate_decr(void);
 
 
 #ifdef __cplusplus
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.3.38/linux/arch/ppc/kernel/open_pic.c	Wed Dec 29 13:13:12 1999
+++ linux/arch/ppc/kernel/open_pic.c	Sat Jan  8 12:59:39 2000
@@ -38,6 +38,7 @@
 	0,
 	0
 };
+int open_pic_irq_offset;
 
 /*
  *  Accesses to the current processor's registers
@@ -69,7 +70,7 @@
  *   -- Cort
  */ 
 #define check_arg_irq(irq) \
-    /*if (irq < 0 || irq >= (NumSources+open_pic.irq_offset)) \
+    /*if (irq < 0 || irq >= (NumSources+open_pic_irq_offset)) \
       printk("openpic.c:%d: illegal irq %d\n", __LINE__, irq);*/
 #define check_arg_cpu(cpu) \
     if (cpu < 0 || cpu >= NumProcessors) \
@@ -212,11 +213,11 @@
 		/* Initialize external interrupts */
 		if ( ppc_md.progress ) ppc_md.progress("openpic ext",0x3bc);
 		/* SIOint (8259 cascade) is special */
-		openpic_initirq(0, 8, open_pic.irq_offset, 1, 1);
+		openpic_initirq(0, 8, open_pic_irq_offset, 1, 1);
 		openpic_mapirq(0, 1<<0);
 		for (i = 1; i < NumSources; i++) {
 			/* Enabled, Priority 8 */
-			openpic_initirq(i, 8, open_pic.irq_offset+i, 0,
+			openpic_initirq(i, 8, open_pic_irq_offset+i, 0,
 					i < OpenPIC_NumInitSenses ? OpenPIC_InitSenses[i] : 1);
 			/* Processor 0 */
 			openpic_mapirq(i, 1<<0);
@@ -416,13 +417,13 @@
 void openpic_enable_irq(u_int irq)
 {
 	check_arg_irq(irq);
-	openpic_clearfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
+	openpic_clearfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
 }
 
 void openpic_disable_irq(u_int irq)
 {
 	check_arg_irq(irq);
-	openpic_setfield(&OpenPIC->Source[irq-irq_desc[irq].handler->irq_offset].Vector_Priority, OPENPIC_MASK);
+	openpic_setfield(&OpenPIC->Source[irq - open_pic_irq_offset].Vector_Priority, OPENPIC_MASK);
 }
 
 /*
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h
--- v2.3.38/linux/arch/ppc/kernel/open_pic.h	Mon Dec 20 18:48:21 1999
+++ linux/arch/ppc/kernel/open_pic.h	Mon Jan 10 18:25:06 2000
@@ -7,4 +7,5 @@
 void openpic_enable_IPI(u_int ipi);
 void do_openpic_setup_cpu(void);
 
+extern int open_pic_irq_offset;
 #endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.3.38/linux/arch/ppc/kernel/pci.c	Thu Jan  6 12:57:47 2000
+++ linux/arch/ppc/kernel/pci.c	Sat Jan  8 12:59:39 2000
@@ -9,6 +9,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/openpic.h>
+#include <linux/errno.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -21,7 +22,7 @@
 
 #include "pci.h"
 
-static void __init pcibios_claim_resources(struct pci_bus *);
+static void __init pcibios_claim_resources(struct list_head *);
 
 unsigned long isa_io_base     = 0;
 unsigned long isa_mem_base    = 0;
@@ -69,10 +70,9 @@
 void __init pcibios_init(void)
 {
 	printk("PCI: Probing PCI hardware\n");
-	ioport_resource.end = ~0L;
 	pci_scan_bus(0, &generic_pci_ops, NULL);
-	pcibios_claim_resources(pci_root);
-	if ( ppc_md.pcibios_fixup )
+	pcibios_claim_resources(&pci_root_buses);
+	if (ppc_md.pcibios_fixup)
 		ppc_md.pcibios_fixup();
 }
 
@@ -161,4 +161,76 @@
 void __init
 pcibios_align_resource(void *data, struct resource *res, unsigned long size)
 {
+}
+
+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;
+}
+
+/*
+ * Assign new address to PCI resource.  We hope our resource information
+ * is complete.  We don't re-assign resources unless we are
+ * forced to do so.
+ *
+ * Expects start=0, end=size-1, flags=resource type.
+ */
+
+int pci_assign_resource(struct pci_dev *dev, int i)
+{
+	struct resource *r = &dev->resource[i];
+	struct resource *pr = pci_find_parent_resource(dev, r);
+	unsigned long size = r->end + 1;
+	u32 new, check;
+
+	if (!pr) {
+		printk(KERN_ERR "PCI: Cannot find parent resource for device %s\n", dev->slot_name);
+		return -EINVAL;
+	}
+	if (r->flags & IORESOURCE_IO) {
+		if (allocate_resource(pr, r, size, 0x100, ~0, size, NULL, NULL)) {
+			printk(KERN_ERR "PCI: Allocation of I/O region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
+			return -EBUSY;
+		}
+	} else {
+		if (allocate_resource(pr, r, size, 0x10000, ~0, size, NULL, NULL)) {
+			printk(KERN_ERR "PCI: Allocation of memory region %s/%d (%ld bytes) failed\n", dev->slot_name, i, size);
+			return -EBUSY;
+		}
+	}
+	if (i < 6) {
+		int reg = PCI_BASE_ADDRESS_0 + 4*i;
+		new = r->start | (r->flags & PCI_REGION_FLAG_MASK);
+		pci_write_config_dword(dev, reg, new);
+		pci_read_config_dword(dev, reg, &check);
+		if (new != check)
+			printk(KERN_ERR "PCI: Error while updating region %s/%d (%08x != %08x)\n", dev->slot_name, i, new, check);
+	} else if (i == PCI_ROM_RESOURCE) {
+		r->flags |= PCI_ROM_ADDRESS_ENABLE;
+		pci_write_config_dword(dev, dev->rom_base_reg, r->start | (r->flags & PCI_REGION_FLAG_MASK));
+	}
+	printk("PCI: Assigned addresses %08lx-%08lx to region %s/%d\n", r->start, r->end, dev->slot_name, i);
+	return 0;
 }
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/pmac_nvram.c linux/arch/ppc/kernel/pmac_nvram.c
--- v2.3.38/linux/arch/ppc/kernel/pmac_nvram.c	Tue Dec  7 09:32:41 1999
+++ linux/arch/ppc/kernel/pmac_nvram.c	Sat Jan  8 12:59:39 2000
@@ -10,6 +10,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/prom.h>
+#include <asm/machdep.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
 
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- v2.3.38/linux/arch/ppc/kernel/pmac_time.c	Sat Oct  9 11:47:50 1999
+++ linux/arch/ppc/kernel/pmac_time.c	Sat Jan  8 12:59:39 2000
@@ -24,6 +24,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/machdep.h>
 
 #include "time.h"
 
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/ppc4xx_pic.c linux/arch/ppc/kernel/ppc4xx_pic.c
--- v2.3.38/linux/arch/ppc/kernel/ppc4xx_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc4xx_pic.c	Mon Jan 10 18:25:32 2000
@@ -0,0 +1,205 @@
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: ppc4xx_pic.c
+ *
+ *    Description:
+ *      Interrupt controller driver for PowerPC 4xx-based processors.
+ */
+
+/*
+ * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
+ * 32 possible interrupts, a majority of which are not implemented on
+ * all cores. There are six configurable, external interrupt pins and
+ * there are eight internal interrupts for the on-chip serial port
+ * (SPU), DMA controller, and JTAG controller.
+ *
+ * The PowerPC 405 cores' Universal Interrupt Controller (UIC) has 32
+ * possible interrupts as well. There are seven, configurable external
+ * interrupt pins and there are 17 internal interrupts for the on-chip
+ * serial port, DMA controller, on-chip Ethernet controller, PCI, etc.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include "local_irq.h"
+#include "ppc4xx_pic.h"
+
+
+/* Global Variables */
+
+struct hw_interrupt_type *ppc4xx_pic;
+
+
+/* Function Prototypes */
+
+static void	 ppc403_aic_enable(unsigned int irq);
+static void	 ppc403_aic_disable(unsigned int irq);
+static void	 ppc403_aic_disable_and_ack(unsigned int irq);
+
+static void	 ppc405_uic_enable(unsigned int irq);
+static void	 ppc405_uic_disable(unsigned int irq);
+static void	 ppc405_uic_disable_and_ack(unsigned int irq);
+
+static struct hw_interrupt_type ppc403_aic = {
+	"403GC AIC",
+	NULL,
+	NULL,
+	ppc403_aic_enable,
+	ppc403_aic_disable,
+	ppc403_aic_disable_and_ack,
+	0
+};
+
+static struct hw_interrupt_type ppc405_uic = {
+	"405GP UIC",
+	NULL,
+	NULL,
+	ppc405_uic_enable,
+	ppc405_uic_disable,
+	ppc405_uic_disable_and_ack,
+	0
+};
+
+/*
+ * Document me.
+ */
+void __init
+ppc4xx_pic_init(void)
+{
+	unsigned long ver = PVR_VER(mfspr(SPRN_PVR));
+
+	switch (ver) {
+
+	case PVR_VER(PVR_403GC):
+		/*
+		 * Disable all external interrupts until they are
+		 * explicity requested.
+		 */
+		ppc_cached_irq_mask[0] = 0;
+		mtdcr(DCRN_EXIER, 0);
+
+		ppc4xx_pic = &ppc403_aic;
+		break;
+
+	case PVR_VER(PVR_405GP):
+		ppc4xx_pic = &ppc405_uic;
+		break;
+	}
+
+	return;
+}
+
+/*
+ * XXX - Currently 403-specific!
+ *
+ * Document me.
+ */
+int
+ppc4xx_pic_get_irq(struct pt_regs *regs)
+{
+	int irq;
+	unsigned long bits, mask = (1 << 31);
+
+	/*
+	 * Only report the status of those interrupts that are actually
+	 * enabled.
+	 */
+
+	bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
+
+	/*
+	 * Walk through the interrupts from highest priority to lowest, and
+	 * report the first pending interrupt found.
+	 */
+
+	for (irq = 0; irq < NR_IRQS; irq++, mask >>= 1) {
+		if (bits & mask)
+			break;
+	}
+
+	return (irq);
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc403_aic_enable(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc403_aic_disable(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc403_aic_disable_and_ack(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+	mtdcr(DCRN_EXISR, (1 << (31 - bit)));
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc405_uic_enable(unsigned int irq)
+{
+	/* XXX - Implement me. */
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc405_uic_disable(unsigned int irq)
+{
+	/* XXX - Implement me. */
+}
+
+/*
+ * Document me.
+ */
+static void
+ppc405_uic_disable_and_ack(unsigned int irq)
+{
+	/* XXX - Implement me. */
+}
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/ppc4xx_pic.h linux/arch/ppc/kernel/ppc4xx_pic.h
--- v2.3.38/linux/arch/ppc/kernel/ppc4xx_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc4xx_pic.h	Mon Jan 10 18:25:32 2000
@@ -0,0 +1,36 @@
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: ppc4xx_pic.h
+ *
+ *    Description:
+ *      Interrupt controller driver for PowerPC 4xx-based processors.
+ */
+
+#ifndef	__PPC4XX_PIC_H__
+#define	__PPC4XX_PIC_H__
+
+#include <asm/ptrace.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* External Global Variables */
+
+extern struct hw_interrupt_type *ppc4xx_pic;
+
+
+/* Function Prototypes */
+
+extern void	 ppc4xx_pic_init(void);
+extern int	 ppc4xx_pic_get_irq(struct pt_regs *regs);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PPC4XX_PIC_H__ */
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.38/linux/arch/ppc/kernel/process.c	Mon Dec 20 18:48:21 1999
+++ linux/arch/ppc/kernel/process.c	Mon Jan 10 18:25:32 2000
@@ -287,6 +287,7 @@
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	    struct task_struct * p, struct pt_regs * regs)
 {
+	unsigned long msr;
 	struct pt_regs * childregs, *kregs;
 #ifdef __SMP__
 	extern void ret_from_smpfork(void);
@@ -310,7 +311,8 @@
 #else	
 	kregs->nip = (unsigned long)ret_from_syscall;
 #endif	
-	kregs->msr = MSR_KERNEL;
+	asm volatile("mfmsr %0" : "=r" (msr):);
+	kregs->msr = msr;
 	kregs->gpr[1] = (unsigned long)childregs - STACK_FRAME_OVERHEAD;
 	kregs->gpr[2] = (unsigned long)p;
 	
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.38/linux/arch/ppc/kernel/setup.c	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/kernel/setup.c	Mon Jan 10 18:25:05 2000
@@ -29,8 +29,9 @@
 #endif
 #include <asm/bootx.h>
 #include <asm/machdep.h>
-
+#ifdef CONFIG_OAK
 #include "oak_setup.h"
+#endif /* CONFIG_OAK */
 
 extern void pmac_init(unsigned long r3,
                       unsigned long r4,
@@ -71,7 +72,13 @@
 extern boot_infos_t *boot_infos;
 char saved_command_line[256];
 unsigned char aux_device_present;
-struct int_control_struct int_control;
+struct int_control_struct int_control =
+{
+	__no_use_cli,
+	__no_use_sti,
+	__no_use_restore_flags,
+	__no_use_save_flags
+};
 struct ide_machdep_calls ppc_ide_md;
 int parse_bootinfo(void);
 
@@ -89,20 +96,13 @@
 
 struct machdep_calls ppc_md;
 
-/* copy of the residual data */
-#ifndef CONFIG_8xx
-extern unsigned char __res[sizeof(RESIDUAL)];
-#else
-extern unsigned char __res[sizeof(bd_t)];
-#endif
-
 /*
  * Perhaps we can put the pmac screen_info[] here
  * on pmac as well so we don't need the ifdef's.
  * Until we get multiple-console support in here
  * that is.  -- Cort
  */ 
-#ifndef CONFIG_8xx
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
 struct screen_info screen_info = {
 	0, 25,			/* orig-x, orig-y */
 	0,			/* unused */
@@ -126,7 +126,7 @@
 {
 }
 
-#else /* CONFIG_8xx */
+#else /* CONFIG_4xx || CONFIG_8xx */
 
 /* We need this to satisfy some external references until we can
  * strip the kernel down.
@@ -142,7 +142,7 @@
 	0,			/* orig-video-isVGA */
 	16			/* orig-video-points */
 };
-#endif /* CONFIG_8xx */
+#endif /* !CONFIG_4xx && !CONFIG_8xx */
 
 void machine_restart(char *cmd)
 {
@@ -193,6 +193,7 @@
 	unsigned long len = 0;
 	unsigned long bogosum = 0;
 	unsigned long i;
+	unsigned int pvr;
 	unsigned short maj, min;
 	
 #ifdef __SMP__
@@ -215,45 +216,75 @@
 		len += sprintf(len+buffer,"processor\t: %lu\n",i);
 		len += sprintf(len+buffer,"cpu\t\t:  ");
 
-		switch (GET_PVR >> 16)
+		pvr = GET_PVR;
+	
+		switch (PVR_VER(pvr))
 		{
-		case 1:
+		case 0x0001:
 			len += sprintf(len+buffer, "601\n");
 			break;
-		case 3:
+		case 0x0003:
 			len += sprintf(len+buffer, "603\n");
 			break;
-		case 4:
+		case 0x0004:
 			len += sprintf(len+buffer, "604\n");
 			break;
-		case 6:
+		case 0x0006:
 			len += sprintf(len+buffer, "603e\n");
 			break;
-		case 7:
-			len += sprintf(len+buffer, "603ev\n");
+		case 0x0007:
+			len += sprintf(len+buffer, "603");
+			if (((pvr >> 12) & 0xF) == 1) {
+				pvr ^= 0x00001000;	/* revision fix-up */
+				len += sprintf(len+buffer, "r\n");
+			} else {
+				len += sprintf(len+buffer, "ev\n");
+			}
 			break;
-		case 8:
-			len += sprintf(len+buffer, "750\n");
+		case 0x0008:		/* 740/750(P) */
+		case 0x1008:
+			len += sprintf(len+buffer, "750%s\n",
+				       PVR_VER(pvr) == 0x1008 ? "P" : "");
 			len += sprintf(len+buffer, "temperature \t: %lu C\n",
 				       cpu_temp());
 			break;
-		case 9:
-			len += sprintf(len+buffer, "604e\n");
+		case 0x0009:		/* 604e/604r */
+		case 0x000A:
+			len += sprintf(len+buffer, "604");
+
+			if (PVR_VER(pvr) == 0x000A ||
+			    ((pvr >> 12) & 0xF) != 0) {
+				pvr &= ~0x00003000;	/* revision fix-up */
+				len += sprintf(len+buffer, "r\n");
+			} else {
+				len += sprintf(len+buffer, "e\n");
+			}
 			break;
-		case 10:
-			len += sprintf(len+buffer, "604ev5 (MachV)\n");
+		case 0x000C:
+			len += sprintf(len+buffer, "7400\n");
 			break;
-		case 12:
-			len += sprintf(len+buffer, "7400 (G4)\n");
+		case 0x0020:
+			len += sprintf(len+buffer, "403G");
+			switch ((pvr >> 8) & 0xFF) {
+			case 0x02:
+				len += sprintf(len+buffer, "C\n");    
+				break;				      
+			case 0x14:
+				len += sprintf(len+buffer, "CX\n");
+				break;
+			}
 			break;
-		case 50:
+		case 0x0050:
 			len += sprintf(len+buffer, "821\n");
-		case 80:
-			len += sprintf(len+buffer, "860\n");
+			break;
+		case 0x0081:
+			len += sprintf(len+buffer, "8240\n");
+			break;
+		case 0x4011:
+			len += sprintf(len+buffer, "405GP\n");
 			break;
 		default:
-			len += sprintf(len+buffer, "unknown (%lx)\n",
-				       GET_PVR>>16);
+			len += sprintf(len+buffer, "unknown (%08x)\n", pvr);
 			break;
 		}
 		
@@ -292,6 +323,22 @@
 			len += ppc_md.setup_residual(buffer + len);
 		}
 		
+		switch (PVR_VER(pvr))
+		{
+		case 0x0020:
+			maj = PVR_MAJ(pvr) + 1;
+			min = PVR_MIN(pvr);
+			break;
+		case 0x1008:
+			maj = ((pvr >> 8) & 0xFF) - 1;
+			min = pvr & 0xFF;
+			break;
+		default:
+			maj = (pvr >> 8) & 0xFF;
+			min = pvr & 0xFF;
+			break;
+		}
+
 		len += sprintf(len+buffer, "revision\t: %hd.%hd\n", maj, min);
 
 		len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
@@ -362,11 +409,6 @@
 identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 		 unsigned long r6, unsigned long r7)
 {
-	int_control.int_sti = __no_use_sti;
-	int_control.int_cli = __no_use_cli;
-	int_control.int_save_flags = __no_use_save_flags;
-	int_control.int_restore_flags = __no_use_restore_flags;
-
 	parse_bootinfo();
 	
 	if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.3.38/linux/arch/ppc/kernel/time.c	Wed Oct 27 16:34:12 1999
+++ linux/arch/ppc/kernel/time.c	Mon Jan 10 18:25:06 2000
@@ -68,7 +68,7 @@
  * with interrupts disabled.
  * We set it up to overflow again in 1/HZ seconds.
  */
-void timer_interrupt(struct pt_regs * regs)
+int timer_interrupt(struct pt_regs * regs)
 {
 	int dval, d;
 	unsigned long cpu = smp_processor_id();
@@ -141,6 +141,7 @@
 		ppc_md.heartbeat();
 	
 	hardirq_exit(cpu);
+	return 1; /* lets ret_from_int know we can do checks */
 }
 
 /*
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/time.h linux/arch/ppc/kernel/time.h
--- v2.3.38/linux/arch/ppc/kernel/time.h	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/time.h	Mon Jan 10 18:25:06 2000
@@ -6,8 +6,11 @@
  * Paul Mackerras' version and mine for PReP and Pmac.
  */
 
+#include <linux/config.h>
 #include <linux/mc146818rtc.h>
 
+#include <asm/processor.h>
+
 /* time.c */
 extern unsigned decrementer_count;
 extern unsigned count_period_num;
@@ -22,13 +25,18 @@
 /* Accessor functions for the decrementer register. */
 static __inline__ unsigned int get_dec(void)
 {
-	unsigned int ret;
-
-	asm volatile("mfspr %0,22" : "=r" (ret) :);
-	return ret;
+#if defined(CONFIG_4xx)
+	return (mfspr(SPRN_PIT));
+#else
+	return (mfspr(SPRN_DEC));
+#endif
 }
 
 static __inline__ void set_dec(unsigned int val)
 {
-	asm volatile("mtspr 22,%0" : : "r" (val));
+#if defined(CONFIG_4xx)
+	mtspr(SPRN_PIT, val);
+#else
+	mtspr(SPRN_DEC, val);
+#endif
 }
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.3.38/linux/arch/ppc/kernel/traps.c	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/kernel/traps.c	Mon Jan 10 18:25:06 2000
@@ -194,7 +194,6 @@
 ProgramCheckException(struct pt_regs *regs)
 {
 #if defined(CONFIG_4xx)
-	unsigned int instr;
 	unsigned int esr = mfspr(SPRN_ESR);
 
 	if (esr & ESR_PTR) {
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/mm/4xx_tlb.c linux/arch/ppc/mm/4xx_tlb.c
--- v2.3.38/linux/arch/ppc/mm/4xx_tlb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/4xx_tlb.c	Mon Jan 10 18:25:32 2000
@@ -0,0 +1,397 @@
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: 4xx_tlb.c
+ *
+ *    Description:
+ *      Routines for manipulating the TLB on PowerPC 400-class processors.
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+
+/* Preprocessor Defines */
+
+#if !defined(TRUE) || TRUE != 1
+#define TRUE    1
+#endif
+
+#if !defined(FALSE) || FALSE != 0
+#define FALSE   0
+#endif
+
+
+/* Function Macros */
+
+
+/* Type Definitios */
+
+typedef struct pin_entry_s {
+	unsigned int	e_pinned: 1,	/* This TLB entry is pinned down. */
+			e_used: 23;	/* Number of users for this mapping. */
+} pin_entry_t;
+
+
+/* Global Variables */
+
+static pin_entry_t pin_table[PPC4XX_TLB_SIZE];
+
+
+/* Function Prototypes */
+
+
+void
+PPC4xx_tlb_pin(unsigned long va, unsigned long pa, int pagesz, int cache)
+{
+	int i, found = FALSE;
+	unsigned long tag, data;
+	unsigned long opid;
+
+	opid = mfspr(SPRN_PID);
+	mtspr(SPRN_PID, 0);
+
+	data = (pa & TLB_RPN_MASK) | TLB_WR;
+
+	if (cache)
+		data |= (TLB_EX | TLB_I);
+	else
+		data |= (TLB_G | TLB_I);
+
+	tag = (va & TLB_EPN_MASK) | TLB_VALID | pagesz;
+
+	for (i = 0; i < PPC4XX_TLB_SIZE; i++) {
+		if (pin_table[i].e_pinned == FALSE) {
+			found = TRUE;
+			break;
+		}
+	}
+
+	if (found) {
+		/* printk("Pinning %#x -> %#x in entry %d...\n", va, pa, i); */
+		asm("tlbwe %0,%1,1" : : "r" (data), "r" (i));
+		asm("tlbwe %0,%1,0" : : "r" (tag), "r" (i));
+		asm("isync");
+		pin_table[i].e_pinned = found;
+	}
+
+	mtspr(SPRN_PID, opid);
+	return;
+}
+
+void
+PPC4xx_tlb_unpin(unsigned long va, unsigned long pa, int size)
+{
+	/* XXX - To beimplemented. */
+}
+
+void
+PPC4xx_tlb_flush_all(void)
+{
+	int i;
+	unsigned long flags, opid;
+
+	save_flags(flags);
+	cli();
+
+	opid = mfspr(SPRN_PID);
+	mtspr(SPRN_PID, 0);
+
+	for (i = 0; i < PPC4XX_TLB_SIZE; i++) {
+		unsigned long ov = 0;
+
+		if (pin_table[i].e_pinned)
+			continue;
+
+		asm("tlbwe %0,%1,0" : : "r" (ov), "r" (i));
+		asm("tlbwe %0,%1,1" : : "r" (ov), "r" (i));
+	}
+
+	asm("sync;isync");
+
+	mtspr(SPRN_PID, opid);
+	restore_flags(flags);
+}
+
+void
+PPC4xx_tlb_flush(unsigned long va, int pid)
+{
+	unsigned long i, tag, flags, found = 1, opid;
+
+	save_flags(flags);
+	cli();
+
+	opid = mfspr(SPRN_PID);
+	mtspr(SPRN_PID, pid);
+
+	asm("tlbsx. %0,0,%2;beq 1f;li %1,0;1:" : "=r" (i), "=r" (found) : "r" (va));
+
+	if (found && pin_table[i].e_pinned == 0) {
+		asm("tlbre %0,%1,0" : "=r" (tag) : "r" (i));
+		tag &= ~ TLB_VALID;
+		asm("tlbwe %0,%1,0" : : "r" (tag), "r" (i));
+	}
+
+	mtspr(SPRN_PID, opid);
+
+	restore_flags(flags);
+}
+
+#if 0
+/*
+ * TLB miss handling code.
+ */
+
+/*
+ * Handle TLB faults. We should push this back to assembly code eventually.
+ * Caller is responsible for turning off interrupts ...
+ */
+static inline void
+tlbDropin(unsigned long tlbhi, unsigned long tlblo) {
+	/*
+	 * Avoid the divide at the slight cost of a little too
+	 * much emphasis on the last few entries.
+	 */
+	unsigned long rand = mfspr(SPRN_TBLO);
+	rand &= 0x3f;
+        rand += NTLB_WIRED;
+        if (rand >= NTLB)
+		rand -= NTLB_WIRED;
+
+	asm("tlbwe %0,%1,1" : : "r" (tlblo), "r" (rand));
+	asm("tlbwe %0,%1,0" : : "r" (tlbhi), "r" (rand));
+	asm("isync;sync");
+}
+
+static inline void
+mkTlbEntry(unsigned long addr, pte_t *pte) {
+	unsigned long tlbhi;
+	unsigned long tlblo;
+	int found = 1;
+	int idx;
+
+	/*
+	 * Construct the TLB entry.
+	 */
+	tlbhi = addr & ~(PAGE_SIZE-1);
+	tlblo = virt_to_phys(pte_page(*pte)) & TLBLO_RPN;
+	if (pte_val(*pte) & _PAGE_HWWRITE)
+		tlblo |= TLBLO_WR;
+	if (pte_val(*pte) & _PAGE_NO_CACHE)
+		tlblo |= TLBLO_I;
+	tlblo |= TLBLO_EX;
+	if (addr < KERNELBASE)
+		tlblo |= TLBLO_Z_USER;
+	tlbhi |= TLBHI_PGSZ_4K;
+	tlbhi |= TLBHI_VALID;
+
+	/*
+	 * See if a match already exists in the TLB.
+	 */
+	asm("tlbsx. %0,0,%2;beq 1f;li %1,0;1:" : "=r" (idx), "=r" (found) : "r" (tlbhi));
+	if (found) {
+		/*
+		 * Found an existing entry. Just reuse the index.
+		 */
+		asm("tlbwe %0,%1,0" : : "r" (tlbhi), "r" (idx));
+		asm("tlbwe %0,%1,1" : : "r" (tlblo), "r" (idx));
+	}
+	else {
+		/*
+		 * Do the more expensive operation
+		 */
+		tlbDropin(tlbhi, tlblo);
+	}
+}
+
+/*
+ * Mainline of the TLB miss handler. The above inline routines should fold into
+ * this one, eliminating most function call overhead.
+ */
+#ifdef TLBMISS_DEBUG
+volatile unsigned long miss_start;
+volatile unsigned long miss_end;
+#endif
+
+static inline int tlbMiss(struct pt_regs *regs, unsigned long badaddr, int wasWrite)
+{
+	int spid, ospid;
+	struct mm_struct *mm;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	if (!user_mode(regs) && (badaddr >= KERNELBASE)) {
+		mm = task[0]->mm;
+		spid = 0;
+#ifdef TLBMISS_DEBUG
+                miss_start = 0;
+#endif
+	}
+	else {
+		mm = current->mm;
+		spid = mfspr(SPRN_PID);
+#ifdef TLBMISS_DEBUG
+                miss_start = 1;
+#endif
+	}
+#ifdef TLBMISS_DEBUG
+        store_cache_range((unsigned long)&miss_start, sizeof(miss_start));
+#endif
+
+	pgd = pgd_offset(mm, badaddr);
+	if (pgd_none(*pgd))
+		goto NOGOOD;
+
+	pmd = pmd_offset(pgd, badaddr);
+	if (pmd_none(*pmd))
+		goto NOGOOD;
+
+	pte = pte_offset(pmd, badaddr);
+	if (pte_none(*pte))
+		goto NOGOOD;
+	if (!pte_present(*pte))
+		goto NOGOOD;
+#if 1
+        prohibit_if_guarded(badaddr, sizeof(int));
+#endif
+	if (wasWrite) {
+		if (!pte_write(*pte)) {
+			goto NOGOOD;
+		}
+		set_pte(pte, pte_mkdirty(*pte));
+	}
+	set_pte(pte, pte_mkyoung(*pte));
+
+	ospid = mfspr(SPRN_PID);
+	mtspr(SPRN_PID, spid);
+	mkTlbEntry(badaddr, pte);
+	mtspr(SPRN_PID, ospid);
+
+#ifdef TLBMISS_DEBUG
+        miss_end = 0;
+        store_cache_range((unsigned long)&miss_end, sizeof(miss_end));
+#endif
+	return 0;
+
+NOGOOD:
+#ifdef TLBMISS_DEBUG
+        miss_end = 1;
+        store_cache_range((unsigned long)&miss_end, sizeof(miss_end));
+#endif
+        return 1;
+}
+
+/*
+ * End TLB miss handling code.
+ */
+/* ---------- */
+
+/*
+ * Used to flush the TLB if the page fault handler decides to change
+ * something.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) {
+	int spid;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	if (addr >= KERNELBASE)
+		spid = 0;
+	else
+		spid = vma->vm_mm->context;
+	tlbFlush1(addr, spid);
+
+	restore_flags(flags);
+}
+
+/*
+ * Given a virtual address in the current address space, make
+ * sure the associated physical page is present in memory,
+ * and if the data is to be modified, that any copy-on-write
+ * actions have taken place.
+ */
+unsigned long make_page_present(unsigned long p, int rw) {
+        pte_t *pte;
+        char c;
+
+        get_user(c, (char *) p);
+
+        pte = findPTE(current->mm, p);
+        if (pte_none(*pte) || !pte_present(*pte))
+            debug("make_page_present didn't load page", 0);
+
+        if (rw) {
+            /*
+            * You have to write-touch the page, so that
+            * zero-filled pages are forced to be copied
+            * rather than still pointing at the zero
+            * page.
+            */
+            extern void tlbFlush1(unsigned long, int);
+            tlbFlush1(p, get_context());
+            put_user(c, (char *) p);
+            if (!pte_write(*pte))
+                debug("make_page_present didn't make page writable", 0);
+
+            tlbFlush1(p, get_context());
+        }
+        return pte_page(*pte);
+}
+
+void DataTLBMissException(struct pt_regs *regs)
+{
+	unsigned long badaddr = mfspr(SPRN_DEAR);
+	int wasWrite = mfspr(SPRN_ESR) & 0x800000;
+	if (tlbMiss(regs, badaddr, wasWrite)) {
+		sti();
+		do_page_fault(regs, badaddr, wasWrite);
+		cli();
+    	}
+}
+
+void InstructionTLBMissException(struct pt_regs *regs)
+{
+	if (!current) {
+		debug("ITLB Miss with no current task", regs);
+		sti();
+		bad_page_fault(regs, regs->nip);
+		cli();
+		return;
+	}
+	if (tlbMiss(regs, regs->nip, 0)) {
+		sti();
+		do_page_fault(regs, regs->nip, 0);
+		cli();
+    	}
+}
+
+void DataPageFault(struct pt_regs *regs)
+{
+	unsigned long badaddr = mfspr(SPRN_DEAR);
+	int wasWrite = mfspr(SPRN_ESR) & 0x800000;
+	sti();
+	do_page_fault(regs, badaddr, wasWrite);
+	cli();
+}
+
+void InstructionPageFault(struct pt_regs *regs)
+{
+	if (!current) {
+		debug("ITLB fault with no current task", regs);
+		sti();
+		bad_page_fault(regs, regs->nip);
+		cli();
+		return;
+	}
+	sti();
+	do_page_fault(regs, regs->nip, 0);
+	cli();
+}
+#endif
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/mm/4xx_tlb.h linux/arch/ppc/mm/4xx_tlb.h
--- v2.3.38/linux/arch/ppc/mm/4xx_tlb.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/4xx_tlb.h	Mon Jan 10 18:25:32 2000
@@ -0,0 +1,35 @@
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: 4xx_tlb.h
+ *
+ *    Description:
+ *      Routines for manipulating the TLB on PowerPC 400-class processors.
+ *
+ */
+
+#ifndef __4XX_TLB_H__
+#define __4XX_TLB_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Function Prototypes */
+
+extern void	 PPC4xx_tlb_pin(unsigned long va, unsigned long pa,
+				int pagesz, int cache);
+extern void	 PPC4xx_tlb_unpin(unsigned long va, unsigned long pa,
+				  int size);
+extern void	 PPC4xx_tlb_flush_all(void);
+extern void	 PPC4xx_tlb_flush(unsigned long va, int pid);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __4XX_TLB_H__ */
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.38/linux/arch/ppc/mm/init.c	Mon Dec 20 18:48:21 1999
+++ linux/arch/ppc/mm/init.c	Mon Jan 10 18:25:05 2000
@@ -59,6 +59,10 @@
 
 #include "mem_pieces.h"
 
+#if defined(CONFIG_4xx)
+#include "4xx_tlb.h"
+#endif
+
 #define	PGTOKB(pages)	(((pages) * PAGE_SIZE) >> 10)
 
 int prom_trashed;
@@ -97,6 +101,9 @@
 #ifdef CONFIG_8xx
 unsigned long *m8xx_find_end_of_memory(void);
 #endif /* CONFIG_8xx */
+#ifdef CONFIG_4xx
+unsigned long *oak_find_end_of_memory(void);
+#endif
 static void mapin_ram(void);
 void map_page(unsigned long va, unsigned long pa, int flags);
 extern void die_if_kernel(char *,struct pt_regs *,long);
@@ -339,9 +346,7 @@
 			continue;
 		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
-	val->totalram <<= PAGE_SHIFT;
-	val->sharedram <<= PAGE_SHIFT;
-	return;
+	val->mem_unit = PAGE_SIZE;
 }
 
 void *
@@ -682,7 +687,7 @@
 	int i;
 	unsigned long v, p, s, f;
 
-#ifndef CONFIG_8xx
+#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
 	if (!__map_without_bats) {
 		unsigned long tot, mem_base, bl, done;
 		unsigned long max_size = (256<<20);
@@ -717,7 +722,7 @@
 			       RAM_PAGE);
 		}
 	}
-#endif /* CONFIG_8xx */
+#endif /* !CONFIG_4xx && !CONFIG_8xx */
 
 	for (i = 0; i < phys_mem.n_regions; ++i) {
 		v = (ulong)__va(phys_mem.regions[i].address);
@@ -846,6 +851,31 @@
  * still be merged.
  * -- Cort
  */
+#if defined(CONFIG_4xx)
+void __init
+MMU_init(void)
+{
+	PPC4xx_tlb_pin(KERNELBASE, 0, TLB_PAGESZ(PAGESZ_16M), 1);
+	PPC4xx_tlb_pin(OAKNET_IO_BASE, OAKNET_IO_BASE, TLB_PAGESZ(PAGESZ_4K), 0);
+        end_of_DRAM = oak_find_end_of_memory();
+
+        /* Map in all of RAM starting at KERNELBASE */
+
+        mapin_ram();
+
+        /* Zone 0 - kernel (above 0x80000000), zone 1 - user */
+
+        mtspr(SPRN_ZPR, 0x2aaaaaaa);
+        mtspr(SPRN_DCWR, 0x00000000);	/* all caching is write-back */
+
+        /* Cache 128MB of space starting at KERNELBASE. */
+
+        mtspr(SPRN_DCCR, 0x00000000);
+        /* flush_instruction_cache(); XXX */
+        mtspr(SPRN_ICCR, 0x00000000);
+        
+}
+#else
 void __init MMU_init(void)
 {
 	if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111);
@@ -947,6 +977,7 @@
 #endif /* CONFIG_8xx */
 	if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211);
 }
+#endif /* CONFIG_4xx */
 
 /*
  * Initialize the bootmem system and give it all the memory we
@@ -1037,29 +1068,21 @@
  */
 void __init paging_init(void)
 {
+	unsigned int zones_size[MAX_NR_ZONES], i;
+
 	/*
 	 * Grab some memory for bad_page and bad_pagetable to use.
 	 */
 	empty_bad_page = alloc_bootmem_pages(PAGE_SIZE);
 	empty_bad_page_table = alloc_bootmem_pages(PAGE_SIZE);
-	{
-		unsigned int zones_size[MAX_NR_ZONES], i;
-		/*
-		 * All pages are DMA-able so this is wrong - the zone code is
-		 * assuming both regions have a value so this is necessary for
-		 * now.
-		 * -- Cort
-		 */
-#if 1
-		for ( i = 1; i < MAX_NR_ZONES; i++ )
-			zones_size[i] = 1<<MAX_ORDER;
-		zones_size[0] = (virt_to_phys(end_of_DRAM) >> PAGE_SHIFT) -
-			((MAX_NR_ZONES-1)*(1<<MAX_ORDER));
-#else
-		zones_size[0] = virt_to_phys(end_of_DRAM) >> PAGE_SHIFT;
-#endif
-		free_area_init(zones_size);
-	}
+
+	/*
+	 * All pages are DMA-able so we put them all in the DMA zone.
+	 */
+	zones_size[0] = virt_to_phys(end_of_DRAM) >> PAGE_SHIFT;
+	for (i = 1; i < MAX_NR_ZONES; i++)
+		zones_size[i] = 0;
+	free_area_init(zones_size);
 }
 
 void __init mem_init(void)
@@ -1404,7 +1427,7 @@
 	}
 	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
 }
-#else /* CONFIG_8xx */
+#elif defined(CONFIG_8xx)
 /*
  * This is a big hack right now, but it may turn into something real
  * someday.
@@ -1432,4 +1455,29 @@
 	set_phys_avail(&phys_mem);
 	return ret;
 }
-#endif /* ndef CONFIG_8xx */
+#endif /* !CONFIG_4xx && !CONFIG_8xx */
+
+#ifdef CONFIG_OAK
+/*
+ * Return the virtual address representing the top of physical RAM
+ * on the Oak board.
+ */
+unsigned long __init *
+oak_find_end_of_memory(void)
+{
+	extern unsigned char __res[];
+
+	unsigned long *ret;
+	bd_t *bip = (bd_t *)__res;
+	
+	phys_mem.regions[0].address = 0;
+	phys_mem.regions[0].size = bip->bi_memsize;
+	phys_mem.n_regions = 1;
+	
+	ret = __va(phys_mem.regions[0].address +
+		   phys_mem.regions[0].size);
+
+	set_phys_avail(&phys_mem);
+	return (ret);
+}
+#endif
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/mm/mem_pieces.c linux/arch/ppc/mm/mem_pieces.c
--- v2.3.38/linux/arch/ppc/mm/mem_pieces.c	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/mm/mem_pieces.c	Mon Jan 10 18:25:06 2000
@@ -209,8 +209,6 @@
 	kstart = __pa(_stext);	/* should be 0 */
 	ksize = PAGE_ALIGN(klimit - _stext);
 
-	printk("kstart = 0x%08lx, ksize = 0x%08lx\n", kstart, ksize);
-
 	mem_pieces_remove(&phys_avail, kstart, ksize, 0);
 	mem_pieces_remove(&phys_avail, 0, 0x4000, 0);
 
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/treeboot/Makefile linux/arch/ppc/treeboot/Makefile
--- v2.3.38/linux/arch/ppc/treeboot/Makefile	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/treeboot/Makefile	Mon Jan 10 18:25:06 2000
@@ -21,9 +21,9 @@
 MKIRIMG	= mkirimg
 
 CFLAGS	= -O -fno-builtin -I$(TOPDIR)/include
-LD_ARGS = -e _start -T ld.script -Ttext 80200000 -Bstatic
+LD_ARGS = -e _start -T ld.script -Ttext 0x00200000 -Bstatic
 
-OBJS	= crt0.o main.o misc.o string.o zlib.o irSect.o
+OBJS	= crt0.o main.o misc.o irSect.o ../coffboot/string.o ../coffboot/zlib.o 
 LIBS	=
 
 treeboot: $(OBJS) ld.script
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/treeboot/crt0.S linux/arch/ppc/treeboot/crt0.S
--- v2.3.38/linux/arch/ppc/treeboot/crt0.S	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/treeboot/crt0.S	Mon Jan 10 18:25:32 2000
@@ -20,7 +20,7 @@
  *
  */
 
-#include "../kernel/ppc_asm.h"
+#include "../kernel/ppc_asm.tmpl"
 
 	.text
 
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/treeboot/main.c linux/arch/ppc/treeboot/main.c
--- v2.3.38/linux/arch/ppc/treeboot/main.c	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/treeboot/main.c	Mon Jan 10 18:25:32 2000
@@ -24,13 +24,22 @@
  *
  */
 
-#include "nonstdio.h"
-#include "zlib.h"
+#include <asm/board.h>
+
+#include "../coffboot/nonstdio.h"
+#include "../coffboot/zlib.h"
 #include "irSect.h"
 
 
 /* Preprocessor Defines */
 
+/*
+ * Location of the IBM boot ROM function pointer address for retrieving
+ * the board information structure.
+ */
+
+#define	BOARD_INFO_VECTOR	0xFFFE0B50
+
 #define	RAM_SIZE	(4 * 1024 * 1024)
 
 #define	RAM_PBASE	0x00000000
@@ -58,6 +67,17 @@
 char *avail_ram;	/* Indicates start of RAM available for heap */
 char *end_avail;	/* Indicates end of RAM available for heap */
 
+bd_t	board_info;
+
+/*
+ * XXX - Until either the IBM boot ROM provides a way of passing arguments to
+ *       the program it launches or until I/O is working in the boot loader,
+ *       this is a good spot to pass in command line arguments to the kernel
+ *       (e.g. console=tty0).
+ */
+
+static char *cmdline = "";
+
 
 /* Function Prototypes */
 
@@ -75,10 +95,16 @@
 {
     void *options;
     int ns, oh, i;
-    unsigned sa, len;
+    unsigned long sa, len;
     void *dst;
     unsigned char *im;
-    unsigned initrd_start, initrd_size;
+    unsigned long initrd_start, initrd_size;
+    bd_t *(*get_board_info)(void) = 
+	    (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR);
+    bd_t *bip = NULL;
+
+    if ((bip = get_board_info()) != NULL)
+	    memcpy(&board_info, bip, sizeof(bd_t));
 
     /* setup_bats(RAM_START); */
 
@@ -96,6 +122,7 @@
 
 	end_avail = (char *)initrd_start;
     } else {
+	initrd_start = initrd_size = 0;
 	end_avail = (char *)RAM_END;
     }
 
@@ -117,16 +144,20 @@
 
 	/* I'm not sure what the 0x200000 parameter is for, but it works. */
 
-	gunzip(dst, 0x200000, cp, &len);
+	gunzip(dst, 0x200000, cp, (int *)&len);
     } else {
 	memmove(dst, im, len);
     }
 
-    /* flush_cache(dst, len); */
+    flush_cache(dst, len);
 
     sa = (unsigned long)dst;
 
-    (*(void (*)())sa)();
+    (*(void (*)())sa)(&board_info,
+		      initrd_start,
+		      initrd_start + initrd_size,
+		      cmdline,
+		      cmdline + strlen(cmdline));
 
     pause();
 }
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/treeboot/misc.S linux/arch/ppc/treeboot/misc.S
--- v2.3.38/linux/arch/ppc/treeboot/misc.S	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/treeboot/misc.S	Mon Jan 10 18:25:05 2000
@@ -6,6 +6,9 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+
+#include "../kernel/ppc_asm.tmpl"
+
 	.text
 
 /*
@@ -15,14 +18,23 @@
  */
 	.global	flush_cache
 flush_cache:
-	addi	4,4,0x1f	/* len = (len + 0x1f) / 0x20 */
-	rlwinm.	4,4,27,5,31
-	mtctr	4
-	beqlr
-1:	dcbf	0,3
-	icbi	0,3
-	addi	3,3,0x20
-	bdnz	1b
+	mfpvr	r5			# Get processor version register
+	extrwi	r5,r5,16,0		# Get the version bits
+	cmpwi	cr0,r5,0x0020		# Is this a 403-based processor?
+	beq	1f			# Yes, it is
+	li	r5,32			# It is not a 403, set to 32 bytes
+	addi	r4,r4,32-1		# len += line_size - 1
+	srwi.	r4,r4,5			# Convert from bytes to lines
+	b	2f
+1:	li	r5,16			# It is a 403, set to 16 bytes
+	addi	r4,r4,16-1		# len += line_size - 1
+	srwi.	r4,r4,4			# Convert from bytes to lines
+2:	mtctr	r4			# Set-up the counter register
+	beqlr				# If it is 0, we are done
+3:	dcbf	r0,r3			# Flush and invalidate the data line
+	icbi	r0,r3			# Invalidate the instruction line
+	add	r3,r3,r5		# Move to the next line
+	bdnz	3b			# Are we done yet?
 	sync
 	isync
-	blr
+	blr				# Return to the caller
diff -u --recursive --new-file v2.3.38/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- v2.3.38/linux/arch/ppc/xmon/start.c	Tue Dec  7 09:32:42 1999
+++ linux/arch/ppc/xmon/start.c	Mon Jan 10 18:25:06 2000
@@ -102,9 +102,11 @@
     if (!scc_initialized)
 	xmon_init_scc();
     for (i = 0; i < nb; ++i) {
+#ifdef CONFIG_ADB	    
 	while ((*sccc & TXRDY) == 0)
 	    if (sys_ctrler == SYS_CTRLER_PMU)
 		pmu_poll();
+#endif /* CONFIG_ADB */
 	buf_access();
 	if ( console && (*p != '\r'))
 		printk("%c", *p);
@@ -195,9 +197,11 @@
     if (!scc_initialized)
 	xmon_init_scc();
     for (i = 0; i < nb; ++i) {
+#ifdef CONFIG_ADB	    
 	while ((*sccc & RXRDY) == 0)
 	    if (sys_ctrler == SYS_CTRLER_PMU)
 		pmu_poll();
+#endif /* CONFIG_ADB */
 	buf_access();
 #if 0	
 	if ( 0/*console*/ )
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/ap1000/apmmu.c linux/arch/sparc/ap1000/apmmu.c
--- v2.3.38/linux/arch/sparc/ap1000/apmmu.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/ap1000/apmmu.c	Sat Jan  8 21:36:20 2000
@@ -907,8 +907,8 @@
 		make_large_page((KERNBASE+phys)>>12,
 				(phys>>12),
 				APMMU_CACHE|APMMU_PRIV|APMMU_VALID);
-	init_mm.mmap->vm_start = page_offset = KERNBASE;
-	stack_top = page_offset - PAGE_SIZE;
+	init_mm.mmap->vm_start = PAGE_OFFSET;
+	stack_top = PAGE_OFFSET - PAGE_SIZE;
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S
--- v2.3.38/linux/arch/sparc/kernel/etrap.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/etrap.S	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.30 1999/08/14 03:51:08 anton Exp $
+/* $Id: etrap.S,v 1.31 2000/01/08 16:38:18 anton Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
@@ -278,7 +278,7 @@
 C_LABEL(tsetup_srmmu_stackchk):
 	/* Check results of callers andcc %sp, 0x7, %g0 */
 	bne	trap_setup_user_stack_is_bolixed
-	 GET_PAGE_OFFSET(glob_tmp)
+	 sethi   %hi(PAGE_OFFSET), %glob_tmp
 
 	cmp	%glob_tmp, %sp
 	bleu,a	1f
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v2.3.38/linux/arch/sparc/kernel/rtrap.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/rtrap.S	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.52 1999/08/14 03:51:18 anton Exp $
+/* $Id: rtrap.S,v 1.53 2000/01/08 16:38:18 anton Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -297,7 +297,7 @@
 	.globl	C_LABEL(srmmu_rett_stackchk)
 C_LABEL(srmmu_rett_stackchk):
 	bne	ret_trap_user_stack_is_bolixed
-	 GET_PAGE_OFFSET(g1)
+	 sethi   %hi(PAGE_OFFSET), %g1
 	cmp	%g1, %fp
 	bleu	ret_trap_user_stack_is_bolixed
 	 mov	AC_M_SFSR, %g1
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.3.38/linux/arch/sparc/kernel/sparc_ksyms.c	Fri Jan  7 19:13:21 2000
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.84 2000/01/07 18:15:14 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.85 2000/01/08 16:38:18 anton Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -123,7 +123,6 @@
 EXPORT_SYMBOL_NOVERS(___up_read);
 EXPORT_SYMBOL_NOVERS(___up_write);
 
-EXPORT_SYMBOL(page_offset);
 EXPORT_SYMBOL(sparc_valid_addr_bitmap);
 
 #ifndef CONFIG_SUN4
@@ -176,7 +175,6 @@
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(enable_irq));
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(disable_irq));
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(__irq_itoa));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_v2p));
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_unlockarea));
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_lockarea));
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_get_scsi_sgl));
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S
--- v2.3.38/linux/arch/sparc/kernel/wof.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/wof.S	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.39 1999/08/14 03:51:35 anton Exp $
+/* $Id: wof.S,v 1.40 2000/01/08 16:38:18 anton Exp $
  * wof.S: Sparc window overflow handler.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -395,7 +395,7 @@
 	 */
 	/* Check results of callers andcc %sp, 0x7, %g0 */
 	bne	spwin_user_stack_is_bolixed
-	 GET_PAGE_OFFSET(glob_tmp)
+	 sethi   %hi(PAGE_OFFSET), %glob_tmp
 	cmp	%glob_tmp, %sp
 	bleu	spwin_user_stack_is_bolixed
 	 mov	AC_M_SFSR, %glob_tmp
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S
--- v2.3.38/linux/arch/sparc/kernel/wuf.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/wuf.S	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.38 1999/08/14 03:51:36 anton Exp $
+/* $Id: wuf.S,v 1.39 2000/01/08 16:38:18 anton Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
@@ -300,7 +300,7 @@
 
 	/* Caller did 'andcc %sp, 0x7, %g0' */
 	bne	fwin_user_stack_is_bolixed
-	 GET_PAGE_OFFSET(l5)
+	 sethi   %hi(PAGE_OFFSET), %l5
 
 	/* Check if the users stack is in kernel vma, then our
 	 * trial and error technique below would succeed for
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/lib/copy_user.S linux/arch/sparc/lib/copy_user.S
--- v2.3.38/linux/arch/sparc/lib/copy_user.S	Sun Oct  4 10:22:42 1998
+++ linux/arch/sparc/lib/copy_user.S	Sat Jan  8 21:36:20 2000
@@ -14,6 +14,7 @@
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
 #include <asm/asmmacro.h>
+#include <asm/page.h>
 
 #define EX(x,y,a,b,z) 				\
 98: 	x,y;					\
@@ -355,7 +356,7 @@
 97:
 	mov	%o2, %g3
 fixupretl:
-	GET_PAGE_OFFSET(g1)
+	sethi   %hi(PAGE_OFFSET), %g1
 	cmp	%o0, %g1
 	blu	1f
 	 cmp	%o1, %g1
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c
--- v2.3.38/linux/arch/sparc/mm/asyncd.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/mm/asyncd.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.18 1999/12/27 06:30:02 anton Exp $
+/*  $Id: asyncd.c,v 1.19 2000/01/08 20:22:16 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -260,10 +260,11 @@
 		save_flags(flags); cli();
 
 		while (!async_queue) {
-			spin_lock_irq(&current->sigmask_lock);
+			spin_lock(&current->sigmask_lock);
 			flush_signals(current);
-			spin_unlock_irq(&current->sigmask_lock);
+			spin_unlock(&current->sigmask_lock);
 			interruptible_sleep_on(&asyncd_wait);
+			__sti(); cli();
 		}
 
 		restore_flags(flags);
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c
--- v2.3.38/linux/arch/sparc/mm/io-unit.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/mm/io-unit.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.18 1999/12/28 04:28:55 anton Exp $
+/* $Id: io-unit.c,v 1.19 2000/01/08 17:01:18 anton Exp $
  * io-unit.c:  IO-UNIT specific routines for memory management.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
@@ -102,7 +102,7 @@
 			goto nexti;
 	iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
 	scan -= npages;
-	iopte = MKIOPTE(mmu_v2p(vaddr & PAGE_MASK));
+	iopte = MKIOPTE(__pa(vaddr & PAGE_MASK));
 	vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);
 	for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {
 		set_bit(scan, iounit->bmap);
@@ -198,7 +198,7 @@
 				struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
 
 				iopte = (iopte_t *)(iounit->page_table + i);
-				*iopte = __iopte(MKIOPTE(mmu_v2p(page)));
+				*iopte = __iopte(MKIOPTE(__pa(page)));
 			}
 		}
 		addr += PAGE_SIZE;
@@ -284,6 +284,6 @@
 	int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
 	struct iounit_struct *iounit = (struct iounit_struct *)sbus->iommu;
 	
-	iounit->page_table[scan] = MKIOPTE(mmu_v2p(((unsigned long)addr) & PAGE_MASK));
+	iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
 	return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
 }
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/mm/iommu.c linux/arch/sparc/mm/iommu.c
--- v2.3.38/linux/arch/sparc/mm/iommu.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/mm/iommu.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.16 1999/12/28 04:28:54 anton Exp $
+/* $Id: iommu.c,v 1.17 2000/01/08 17:01:18 anton Exp $
  * iommu.c:  IOMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -36,13 +36,13 @@
 static inline void iommu_map_dvma_pages_for_iommu(struct iommu_struct *iommu)
 {
 	unsigned long kern_end = (unsigned long) high_memory;
-	unsigned long first = page_offset;
+	unsigned long first = PAGE_OFFSET;
 	unsigned long last = kern_end;
 	iopte_t *iopte = iommu->page_table;
 
 	iopte += ((first - iommu->start) >> PAGE_SHIFT);
 	while(first <= last) {
-		*iopte++ = __iopte(MKIOPTE(mmu_v2p(first)));
+		*iopte++ = __iopte(MKIOPTE(__pa(first)));
 		first += PAGE_SIZE;
 	}
 }
@@ -71,7 +71,7 @@
 	vers = (iommu->regs->control & IOMMU_CTRL_VERS) >> 24;
 	tmp = iommu->regs->control;
 	tmp &= ~(IOMMU_CTRL_RNGE);
-	switch(page_offset & 0xf0000000) {
+	switch(PAGE_OFFSET & 0xf0000000) {
 	case 0xf0000000:
 		tmp |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB);
 		iommu->plow = iommu->start = 0xf0000000;
@@ -135,7 +135,7 @@
 		}
 	}
 	flush_tlb_all();
-	iommu->regs->base = mmu_v2p((unsigned long) iommu->page_table) >> 4;
+	iommu->regs->base = __pa((unsigned long) iommu->page_table) >> 4;
 	iommu_invalidate(iommu->regs);
 
 	sbus->iommu = iommu;
@@ -249,10 +249,10 @@
 
 			set_pte(ptep, pte_val(mk_pte(page, dvma_prot)));
 			if (ipte_cache != 0) {
-				iopte_val(*iopte++) = MKIOPTE(mmu_v2p(page));
+				iopte_val(*iopte++) = MKIOPTE(__pa(page));
 			} else {
 				iopte_val(*iopte++) =
-					MKIOPTE(mmu_v2p(page)) & ~IOPTE_CACHE;
+					MKIOPTE(__pa(page)) & ~IOPTE_CACHE;
 			}
 		}
 		addr += PAGE_SIZE;
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c
--- v2.3.38/linux/arch/sparc/mm/loadmmu.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/mm/loadmmu.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.51 1999/08/31 06:54:35 davem Exp $
+/* $Id: loadmmu.c,v 1.52 2000/01/08 16:38:20 anton Exp $
  * loadmmu.c:  This code loads up all the mm function pointers once the
  *             machine type has been determined.  It also sets the static
  *             mmu values such as PAGE_NONE, etc.
@@ -19,7 +19,6 @@
 #include <asm/mmu_context.h>
 #include <asm/oplib.h>
 
-unsigned long page_offset = 0xf0000000;
 unsigned long stack_top = 0xf0000000 - PAGE_SIZE;
 
 struct ctx_list *ctx_list_pool;
diff -u --recursive --new-file v2.3.38/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.3.38/linux/arch/sparc/mm/sun4c.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/mm/sun4c.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.182 1999/12/27 06:30:04 anton Exp $
+/* $Id: sun4c.c,v 1.183 2000/01/08 16:38:20 anton Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -68,20 +68,6 @@
 struct sun4c_vac_props sun4c_vacinfo;
 unsigned long sun4c_kernel_faults;
 
-/* convert a virtual address to a physical address and vice
- * versa. Easy on the 4c
- */
-static unsigned long sun4c_v2p(unsigned long vaddr)
-{
-	return (vaddr - PAGE_OFFSET);
-}
-
-static unsigned long sun4c_p2v(unsigned long vaddr)
-{
-	return (vaddr + PAGE_OFFSET);
-}
-
-
 /* Invalidate every sun4c cache line tag. */
 void sun4c_flush_all(void)
 {
@@ -2731,9 +2717,6 @@
 	BTFIXUPSET_CALL(mmu_flush_dma_area, sun4c_flush_dma_area, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(mmu_inval_dma_area, sun4c_inval_dma_area, BTFIXUPCALL_NORM);
 
-        BTFIXUPSET_CALL(mmu_v2p, sun4c_v2p, BTFIXUPCALL_NORM);
-        BTFIXUPSET_CALL(mmu_p2v, sun4c_p2v, BTFIXUPCALL_NORM);
-	
 	/* Task struct and kernel stack allocating/freeing. */
 	BTFIXUPSET_CALL(alloc_task_struct, sun4c_alloc_task_struct, BTFIXUPCALL_NORM);
 
diff -u --recursive --new-file v2.3.38/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c
--- v2.3.38/linux/arch/sparc64/mm/asyncd.c	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/mm/asyncd.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.10 1999/12/15 22:25:02 davem Exp $
+/*  $Id: asyncd.c,v 1.11 2000/01/08 20:22:19 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
@@ -263,10 +263,11 @@
 		save_flags(flags); cli();
 
 		while (!async_queue) {
-			spin_lock_irq(&current->sigmask_lock);
+			spin_lock(&current->sigmask_lock);
 			flush_signals(current);
-			spin_unlock_irq(&current->sigmask_lock);
+			spin_unlock(&current->sigmask_lock);
 			interruptible_sleep_on(&asyncd_wait);
+			__sti(); cli(); /* acquire gloabl_irq_lock */
 		}
 
 		restore_flags(flags);
diff -u --recursive --new-file v2.3.38/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c
--- v2.3.38/linux/drivers/acorn/block/fd1772.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/acorn/block/fd1772.c	Sat Jan  8 17:41:15 2000
@@ -1556,11 +1556,7 @@
 
 static void floppy_release(struct inode *inode, struct file *filp)
 {
-	int drive;
-
-	drive = MINOR(inode->i_rdev) & 3;
-
-	block_fsync(inode, filp);
+	int drive = MINOR(inode->i_rdev) & 3;
 
 	if (fd_ref[drive] < 0)
 		fd_ref[drive] = 0;
diff -u --recursive --new-file v2.3.38/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- v2.3.38/linux/drivers/acorn/block/mfmhd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/acorn/block/mfmhd.c	Sat Jan  8 17:41:15 2000
@@ -1276,7 +1276,6 @@
  */
 static int mfm_release(struct inode *inode, struct file *file)
 {
-	fsync_dev(inode->i_rdev);
 	mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--;
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -u --recursive --new-file v2.3.38/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c
--- v2.3.38/linux/drivers/ap1000/ddv.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/ap1000/ddv.c	Sat Jan  8 21:36:20 2000
@@ -166,7 +166,6 @@
 #if DEBUG
 	printk("ddv_release started\n");
 #endif
-	sync_dev(inode->i_rdev);
 #if DEBUG
 	printk("ddv_release done\n");
 #endif
@@ -386,10 +385,11 @@
 		save_flags(flags); cli();
 
 		while (!rem_queue) {
-			spin_lock_irq(&current->sigmask_lock);
+			spin_lock(&current->sigmask_lock);
 			flush_signals(current);
-			spin_unlock_irq(&current->sigmask_lock);
+			spin_unlock(&current->sigmask_lock);
 			interruptible_sleep_on(&ddv_daemon_wait);
+			__sti(); cli();
 		}
 
 		rem = rem_queue;
diff -u --recursive --new-file v2.3.38/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c
--- v2.3.38/linux/drivers/atm/nicstar.c	Fri Sep 10 23:57:29 1999
+++ linux/drivers/atm/nicstar.c	Mon Jan 10 14:05:32 2000
@@ -502,7 +502,7 @@
       PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
       for (j = 1; j < 4; j++)
       {
-         if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0);
+         if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
 	    break;
       }
       if (j == 4)
diff -u --recursive --new-file v2.3.38/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.3.38/linux/drivers/block/DAC960.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/DAC960.c	Sat Jan  8 17:41:15 2000
@@ -2467,10 +2467,6 @@
       File != NULL && (File->f_flags & O_NONBLOCK))
     goto ModuleOnly;
   /*
-    Force any buffered data to be written.
-  */
-  fsync_dev(Inode->i_rdev);
-  /*
     Decrement the Logical Drive and Controller Usage Counts.
   */
   Controller->LogicalDriveUsageCount[LogicalDriveNumber]--;
diff -u --recursive --new-file v2.3.38/linux/drivers/block/acsi.c linux/drivers/block/acsi.c
--- v2.3.38/linux/drivers/block/acsi.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/acsi.c	Sat Jan  8 17:41:16 2000
@@ -1216,11 +1216,7 @@
 
 static int acsi_release( struct inode * inode, struct file * file )
 {
-	int device;
-
-	sync_dev(inode->i_rdev);
-
-	device = DEVICE_NR(MINOR(inode->i_rdev));
+	int device = DEVICE_NR(MINOR(inode->i_rdev));
 	if (--access_count[device] == 0 && acsi_info[device].removable)
 		acsi_prevent_removal(device, 0);
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.3.38/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.3.38/linux/drivers/block/amiflop.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/amiflop.c	Sat Jan  8 17:41:16 2000
@@ -1686,16 +1686,6 @@
 #endif
 	int drive = MINOR(inode->i_rdev) & 3;
 
-	fsync_dev(inode->i_rdev);
-
-#ifdef DEBUG
-	/* This is now handled in floppy_change, but still useful for debugging */
-	sb = get_super(inode->i_rdev);
-	if (sb)
-		invalidate_inodes(sb);
-	invalidate_buffers(inode->i_rdev);
-#endif
-
 	if (unit[drive].dirty == 1) {
 		del_timer (flush_track_timer + drive);
 		non_int_flush_track (drive);
diff -u --recursive --new-file v2.3.38/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- v2.3.38/linux/drivers/block/ataflop.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/ataflop.c	Sat Jan  8 17:41:16 2000
@@ -1941,11 +1941,7 @@
 
 static int floppy_release( struct inode * inode, struct file * filp )
 {
-	int drive;
-
-	drive = MINOR(inode->i_rdev) & 3;
-
-	block_fsync (filp, filp->f_dentry);
+	int drive = MINOR(inode->i_rdev) & 3;
 
 	if (fd_ref[drive] < 0)
 		fd_ref[drive] = 0;
diff -u --recursive --new-file v2.3.38/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.3.38/linux/drivers/block/cpqarray.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/cpqarray.c	Sat Jan  8 17:41:16 2000
@@ -837,7 +837,6 @@
 	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
 
 	DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
-	fsync_dev(inode->i_rdev);
 
 	hba[ctlr]->drv[dsk].usage_count--;
 	hba[ctlr]->usage_count--;
diff -u --recursive --new-file v2.3.38/linux/drivers/block/cy82c693.c linux/drivers/block/cy82c693.c
--- v2.3.38/linux/drivers/block/cy82c693.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/cy82c693.c	Sat Jan  8 12:38:19 2000
@@ -275,9 +275,9 @@
 
 	/* select primary or secondary channel */
 	if (hwif->index > 0) {  /* drive is on the secondary channel */
-		dev = pci_find_slot(dev, dev->devfn+1);
+		dev = pci_find_slot(dev->bus->number, dev->devfn+1);
 		if (!dev) {
-			printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n");
+			printk(KERN_ERR "%s: tune_drive: Cannot find secondary interface!\n", drive->name);
 			return;
 		}
 	}
diff -u --recursive --new-file v2.3.38/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.38/linux/drivers/block/floppy.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/floppy.c	Sat Jan  8 17:41:16 2000
@@ -3627,11 +3627,7 @@
 
 static int floppy_release(struct inode * inode, struct file * filp)
 {
-	int drive;
-
-	drive = DRIVE(inode->i_rdev);
-
-	block_fsync(filp, filp->f_dentry);
+	int drive = DRIVE(inode->i_rdev);
 
 	if (UDRS->fd_ref < 0)
 		UDRS->fd_ref=0;
diff -u --recursive --new-file v2.3.38/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v2.3.38/linux/drivers/block/hd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/hd.c	Sat Jan  8 17:41:16 2000
@@ -657,10 +657,7 @@
  */
 static int hd_release(struct inode * inode, struct file * file)
 {
-        int target;
-	sync_dev(inode->i_rdev);
-
-	target =  DEVICE_NR(inode->i_rdev);
+        int target =  DEVICE_NR(inode->i_rdev);
 	access_count[target]--;
 	return 0;
 }
diff -u --recursive --new-file v2.3.38/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.38/linux/drivers/block/ide.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/ide.c	Sat Jan  8 17:41:16 2000
@@ -1846,7 +1846,6 @@
 	ide_drive_t *drive;
 
 	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
-		fsync_dev(inode->i_rdev);
 		drive->usage--;
 		if (drive->driver != NULL)
 			DRIVER(drive)->release(inode, file, drive);
diff -u --recursive --new-file v2.3.38/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.38/linux/drivers/block/loop.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/loop.c	Mon Jan 10 14:05:50 2000
@@ -643,7 +643,7 @@
 static int lo_release(struct inode *inode, struct file *file)
 {
 	struct loop_device *lo;
-	int	dev, err;
+	int	dev;
 
 	if (!inode)
 		return 0;
@@ -654,7 +654,6 @@
 	dev = MINOR(inode->i_rdev);
 	if (dev >= max_loop)
 		return 0;
-	err = fsync_dev(inode->i_rdev);
 	lo = &loop_dev[dev];
 	if (lo->lo_refcnt <= 0)
 		printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt);
@@ -665,7 +664,7 @@
 			xfer_funcs[type]->unlock(lo);
 		MOD_DEC_USE_COUNT;
 	}
-	return err;
+	return 0;
 }
 
 static struct block_device_operations lo_fops = {
diff -u --recursive --new-file v2.3.38/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.3.38/linux/drivers/block/md.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/md.c	Sat Jan  8 17:41:16 2000
@@ -675,8 +675,6 @@
 static int md_release (struct inode *inode, struct file *file)
 {
   int minor=MINOR(inode->i_rdev);
-
-  sync_dev (inode->i_rdev);
   md_dev[minor].busy--;
   return 0;
 }
diff -u --recursive --new-file v2.3.38/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.3.38/linux/drivers/block/nbd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/nbd.c	Sat Jan  8 17:41:16 2000
@@ -435,8 +435,6 @@
 	dev = MINOR(inode->i_rdev);
 	if (dev >= MAX_NBD)
 		return -ENODEV;
-	fsync_dev(inode->i_rdev);
-	invalidate_buffers(inode->i_rdev);
 	lo = &nbd_dev[dev];
 	if (lo->refcnt <= 0)
 		printk(KERN_ALERT "nbd_release: refcount(%d) <= 0\n", lo->refcnt);
diff -u --recursive --new-file v2.3.38/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.3.38/linux/drivers/block/paride/pd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/paride/pd.c	Sat Jan  8 17:41:16 2000
@@ -512,15 +512,8 @@
 
 	PD.access--;
 
-        if (!PD.access)  {
-                fsync_dev(devp);
-
-		sb = get_super(devp);
-		if (sb) invalidate_inodes(sb);
-
-                invalidate_buffers(devp);
-		if (PD.removable) pd_doorlock(unit,IDE_DOORUNLOCK);
-	}
+        if (!PD.access && PD.removable)
+		pd_doorlock(unit,IDE_DOORUNLOCK);
 
         MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.3.38/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.3.38/linux/drivers/block/paride/pf.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/paride/pf.c	Sat Jan  8 17:41:16 2000
@@ -447,8 +447,6 @@
 {       kdev_t devp;
 	int	unit;
 
-	struct super_block *sb;
-
         devp = inode->i_rdev;
         unit = DEVICE_NR(devp);
 
@@ -457,15 +455,8 @@
 
 	PF.access--;
 
-	if (!PF.access) {
-                fsync_dev(devp);
-
-		sb = get_super(devp);
-		if (sb) invalidate_inodes(sb);
-
-                invalidate_buffers(devp);
-		if (PF.removable) pf_lock(unit,0);
-        }
+	if (!PF.access && PF.removable)
+		pf_lock(unit,0);
 
         MOD_DEC_USE_COUNT;
 
diff -u --recursive --new-file v2.3.38/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.3.38/linux/drivers/block/ps2esdi.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/ps2esdi.c	Sat Jan  8 17:41:16 2000
@@ -1105,7 +1105,6 @@
 	int dev = DEVICE_NR(inode->i_rdev);
 
 	if (dev < ps2esdi_drives) {
-		sync_dev(inode->i_rdev);
 		access_count[dev]--;
 	}
 	return 0;
diff -u --recursive --new-file v2.3.38/linux/drivers/block/swim3.c linux/drivers/block/swim3.c
--- v2.3.38/linux/drivers/block/swim3.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/swim3.c	Sat Jan  8 17:41:16 2000
@@ -924,8 +924,6 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 
-	block_fsync (filp, filp->f_dentry);
-
 	fs = &floppy_states[devnum];
 	sw = fs->swim3;
 	if (fs->ref_count > 0 && --fs->ref_count == 0) {
diff -u --recursive --new-file v2.3.38/linux/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c
--- v2.3.38/linux/drivers/block/swim_iop.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/swim_iop.c	Sat Jan  8 17:41:16 2000
@@ -449,8 +449,6 @@
 	if (devnum >= floppy_count)
 		return -ENODEV;
 
-	block_fsync (filp, filp->f_dentry);
-
 	fs = &floppy_states[devnum];
 	if (fs->ref_count > 0) fs->ref_count--;
 	return 0;
diff -u --recursive --new-file v2.3.38/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.3.38/linux/drivers/block/xd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/xd.c	Sat Jan  8 17:41:16 2000
@@ -367,17 +367,12 @@
 /* xd_release: release the device */
 static int xd_release (struct inode *inode, struct file *file)
 {
-	int target;
-
-	target= DEVICE_NR(inode->i_rdev);
+	int target = DEVICE_NR(inode->i_rdev);
 	if (target < xd_drives) {
-		sync_dev(inode->i_rdev);
 		xd_access[target]--;
-
 #ifdef MODULE
 		MOD_DEC_USE_COUNT;
 #endif /* MODULE */
-
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.3.38/linux/drivers/block/z2ram.c linux/drivers/block/z2ram.c
--- v2.3.38/linux/drivers/block/z2ram.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/block/z2ram.c	Sat Jan  8 17:41:16 2000
@@ -320,8 +320,6 @@
     if ( current_device == -1 )
 	return 0;     
 
-    sync_dev( inode->i_rdev );
-
     /*
      * FIXME: unmap memory
      */
diff -u --recursive --new-file v2.3.38/linux/drivers/cdrom/aztcd.c linux/drivers/cdrom/aztcd.c
--- v2.3.38/linux/drivers/cdrom/aztcd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/cdrom/aztcd.c	Sat Jan  8 17:41:16 2000
@@ -1593,8 +1593,6 @@
   MOD_DEC_USE_COUNT;
   if (!--azt_open_count) {
 	azt_invalidate_buffers();
-	sync_dev(inode->i_rdev);             /*??? isn't it a read only dev?*/
-	invalidate_buffers(inode -> i_rdev);
 	aztUnlockDoor();
         if (azt_auto_eject)
            aztSendCmd(ACMD_EJECT);
diff -u --recursive --new-file v2.3.38/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.38/linux/drivers/cdrom/cdrom.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/cdrom/cdrom.c	Sat Jan  8 17:41:16 2000
@@ -640,11 +640,6 @@
 		!(fp && fp->f_flags & O_NONBLOCK);
 	cdo->release(cdi);
 	if (cdi->use_count == 0) {      /* last process that closes dev*/
-		struct super_block *sb;
-		sync_dev(dev);
-		sb = get_super(dev);
-		if (sb) invalidate_inodes(sb);
-		invalidate_buffers(dev);
 		if (opened_for_data &&
 		    cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY))
 			cdo->tray_move(cdi, 1);
diff -u --recursive --new-file v2.3.38/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c
--- v2.3.38/linux/drivers/cdrom/gscd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/cdrom/gscd.c	Sat Jan  8 17:41:16 2000
@@ -418,8 +418,6 @@
 #endif
 
 	gscd_bn = -1;
-	sync_dev(inode->i_rdev);
-	invalidate_buffers(inode -> i_rdev);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -u --recursive --new-file v2.3.38/linux/drivers/cdrom/optcd.c linux/drivers/cdrom/optcd.c
--- v2.3.38/linux/drivers/cdrom/optcd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/cdrom/optcd.c	Sat Jan  8 17:41:16 2000
@@ -1935,8 +1935,6 @@
 	if (!--open_count) {
 		toc_uptodate = 0;
 		opt_invalidate_buffers();
-		sync_dev(ip -> i_rdev);
-		invalidate_buffers(ip -> i_rdev);
 	 	status = exec_cmd(COMUNLOCK);	/* Unlock door */
 		if (status < 0) {
 			DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
diff -u --recursive --new-file v2.3.38/linux/drivers/cdrom/sjcd.c linux/drivers/cdrom/sjcd.c
--- v2.3.38/linux/drivers/cdrom/sjcd.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/cdrom/sjcd.c	Sat Jan  8 17:41:16 2000
@@ -1413,8 +1413,6 @@
 #endif
   if( --sjcd_open_count == 0 ){
     sjcd_invalidate_buffers();
-    sync_dev( inode->i_rdev );
-    invalidate_buffers( inode->i_rdev );
     s = sjcd_tray_unlock();
     if( s < 0 || !sjcd_status_valid || sjcd_command_failed ){
 #if defined( SJCD_DIAGNOSTIC )
diff -u --recursive --new-file v2.3.38/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c
--- v2.3.38/linux/drivers/cdrom/sonycd535.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/cdrom/sonycd535.c	Sat Jan  8 17:41:16 2000
@@ -1451,7 +1451,6 @@
 		sony_usage--;
 	}
 	if (sony_usage == 0) {
-		sync_dev(inode->i_rdev);
 		check_drive_status();
 
 		if (sony_audio_status != CDROM_AUDIO_PLAY) {
diff -u --recursive --new-file v2.3.38/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.3.38/linux/drivers/char/bttv.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/char/bttv.c	Sat Jan  8 12:54:54 2000
@@ -386,7 +386,7 @@
 
 	bttv_bit_setscl(btv,1);
 	bttv_bit_setsda(btv,1);
-	
+
 	return i2c_bit_add_bus(&btv->i2c_adap);
 }
 
@@ -428,15 +428,15 @@
 }
 
 /* read EEPROM */
-static void readee(struct bttv *btv, unsigned char *eedata)
+static void readee(struct bttv *btv, unsigned char *eedata, int addr)
 {
 	int i;
         
-	if (I2CWrite(btv, 0xa0, 0, -1, 0)<0) {
+	if (I2CWrite(btv, addr, 0, -1, 0)<0) {
 		printk(KERN_WARNING "bttv: readee error\n");
 		return;
 	}
-	btv->i2c_client.addr = 0xa0 >> 1;
+	btv->i2c_client.addr = addr >> 1;
 	for (i=0; i<256; i+=16) {
 		if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) {
 			printk(KERN_WARNING "bttv: readee error\n");
@@ -486,7 +486,7 @@
 static void
 hauppauge_eeprom(struct bttv *btv)
 {
-        readee(btv, eeprom_data);
+        readee(btv, eeprom_data, 0xa0);
         if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) 
         {
                 btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
@@ -515,7 +515,10 @@
  *  driver, but using BTTV functions */
 static void init_PXC200(struct bttv *btv)
 {
-	int tmp;
+	static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
+				    0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+				    0x00 };
+	int i,tmp;
 
 	/*	Initialise GPIO-connevted stuff */
 	btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */
@@ -537,39 +540,37 @@
 	 *	argument so the numbers are different */
 	
 	printk(KERN_INFO "Initialising 12C508 PIC chip ...\n");
-	
-	tmp=I2CWrite(btv,0x1E,0x08,0,1);
-	printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x09,0,1);
-	printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x0a,0,1);
-	printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x0b,0,1);
-	printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x0c,0,1);
-	printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x0d,0,1);
-	printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x01,0,1);
-	printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x02,0,1);
-	printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x03,0,1);
-	printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x04,0,1);
-	printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x05,0,1);
-	printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x06,0,1);
-	printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	tmp=I2CWrite(btv,0x1E,0x00,0,1);
-	printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL));
-	
+
+	for (i = 0; i < sizeof(vals)/sizeof(int); i++) {
+		tmp=I2CWrite(btv,0x1E,vals[i],0,1);
+		printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",
+		       tmp,I2CRead(btv,0x1F,NULL));
+	}
 	printk(KERN_INFO "PXC200 Initialised.\n");
 }
 
 /* ----------------------------------------------------------------------- */
 
+static struct VENDOR {
+	int id;
+	char *name;
+} vendors[] = {
+	{ 0x0070, "Hauppauge" },
+	{ 0x144f, "Askey" },
+	{ -1, NULL }
+};
+
+static struct CARD {
+	int id;
+	int vid;
+	int cardnr;
+	char *name;
+} cards[] = {
+	{ 0x13eb, 0x0070, BTTV_HAUPPAUGE878,  "WinTV Theater" },
+	{ 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView"   },
+	{ -1, -1, -1, NULL }
+};
+
 struct tvcard
 {
         char *name;
@@ -677,8 +678,8 @@
 	  1,1,1,1,0 },
 
 	/* 0x18 */
-	{ "Magic TView CPH061 (bt878)",
-	  3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0, 0, 0, 0},0,
+        { "Askey/Typhoon/Anubis Magic TView CPH051/061 (bt878)",
+	  3, 1, 0, 2, 0xe00, { 2, 3, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
 	  1,1,1,1,0 },
         { "Terratec/Vobis TV-Boostar",
           3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0,
@@ -709,15 +710,58 @@
 	{ "Intel Create and Share PCI",
 	  4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0,
 	  1,1,1,1,0 },
-        { "Askey/Typhoon/Anubis Magic TView",
-	  3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0,
-	  1,1,1,1,0 },
 	{ "Terratec TerraTValue",
-          3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
+          3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0,
 	  1,1,1,1,0 },
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
 
+static void
+dump_eeprom(struct bttv *btv, int addr)
+{
+	int i,id1,id2,n1,n2;
+
+	printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr);
+        readee(btv, eeprom_data,addr);
+	for (i = 0; i < 256;) {
+		printk(KERN_DEBUG "  %02x:",i);
+		do {
+			printk(" %02x",eeprom_data[i++]);
+		} while (i % 16);
+		printk("\n");
+	}
+	id1 = (eeprom_data[252] << 8) | (eeprom_data[253]);
+	id2 = (eeprom_data[254] << 8) | (eeprom_data[255]);
+	if (id1 != 0 && id1 != 0xffff &&
+	    id2 != 0 && id2 != 0xffff) {
+		n1 = -1;
+		n2 = -1;
+		for (i = 0; vendors[i].id != -1; i++)
+			if (vendors[i].id == id2)
+				n2 = i;
+		for (i = 0; cards[i].id != -1; i++)
+			if (cards[i].id  == id1 &&
+			    cards[i].vid == id2)
+				n1 = i;
+		if (n1 != -1 && n2 != -1) {
+			printk(KERN_INFO "  id: %s (0x%04x), vendor: %s (0x%04x)\n",
+			       cards[n1].name,id1,vendors[n2].name,id2);
+			printk(KERN_INFO "  => card=%d (%s)\n",
+			       cards[n1].cardnr,tvcards[cards[n1].cardnr].name);
+#if 1
+			/* not yet, but that's the plan for autodetect... */
+			btv->type = cards[n1].cardnr;
+#endif
+		} else {
+			printk(KERN_INFO "  id: %s (0x%04x), vendor: %s (0x%04x)\n",
+			       (n1 != -1) ? cards[n1].name   : "unknown", id1,
+			       (n2 != -1) ? vendors[n2].name : "unknown", id2);
+			printk(KERN_INFO "  please mail card type, id + vendor to ");
+			printk(" kraxel@goldbach.in-berlin.de\n");
+		}
+	}
+}
+
 /* ----------------------------------------------------------------------- */
 
 static void audio(struct bttv *btv, int mode, int no_irq_context)
@@ -2883,6 +2927,13 @@
 		}
 	}
 
+#if 1
+	/* DEBUG: dump eeprom content if available */
+	if (I2CRead(btv, 0xa0, "eeprom")>=0) {
+		dump_eeprom(btv,0xa0);
+	}
+#endif
+
 	/* print which board we have found */
 	printk(KERN_INFO "bttv%d: model: ",btv->nr);
 
@@ -2917,7 +2968,8 @@
         if (btv->type == BTTV_HAUPPAUGE878	||
 	    btv->type == BTTV_CONFERENCETV	||
 	    btv->type == BTTV_PIXVIEWPLAYTV	||
-	    btv->type == BTTV_AVERMEDIA98) {
+	    btv->type == BTTV_AVERMEDIA98	||
+	    btv->type == BTTV_MAGICTVIEW061) {
                 btv->pll.pll_ifreq=28636363;
                 btv->pll.pll_crystal=BT848_IFORM_XT0;
         }
@@ -2952,8 +3004,8 @@
 			request_module("tda9855");
 	}
 
-	if (tvcards[btv->type].tea63xx &&
-	    I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0) {
+	if (tvcards[btv->type].tea63xx /* &&
+	    I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0 */) {
 		if (autoload)
 			request_module("tea6300");
 	}
@@ -3553,7 +3605,11 @@
 #endif
 {
 	int i;
-  
+
+	printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
+	       (BTTV_VERSION_CODE >> 16) & 0xff,
+	       (BTTV_VERSION_CODE >> 8) & 0xff,
+	       BTTV_VERSION_CODE & 0xff);
 	handle_chipset();
 	if (find_bt848()<=0)
 		return -EIO;
diff -u --recursive --new-file v2.3.38/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.3.38/linux/drivers/char/bttv.h	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/bttv.h	Sat Jan  8 12:54:54 2000
@@ -21,7 +21,7 @@
 #ifndef _BTTV_H_
 #define _BTTV_H_
 
-#define BTTV_VERSION_CODE 0x00070b
+#define BTTV_VERSION_CODE 0x00070d
 
 #include <linux/types.h>
 #include <linux/wait.h>
@@ -247,32 +247,6 @@
 #define BTTV_MAXI          0x1b
 #define BTTV_TERRATV       0x1c
 #define BTTV_PXC200        0x1d
-
-#if 0
-#define BTTV_UNKNOWN       0x00
-#define BTTV_MIRO          0x01
-#define BTTV_HAUPPAUGE     0x02
-#define BTTV_STB           0x03
-#define BTTV_INTEL         0x04
-#define BTTV_DIAMOND       0x05 
-#define BTTV_AVERMEDIA     0x06 
-#define BTTV_MATRIX_VISION 0x07 
-#define BTTV_FLYVIDEO      0x08
-#define BTTV_TURBOTV       0x09
-#define BTTV_HAUPPAUGE878  0x0a
-#define BTTV_MIROPRO       0x0b
-#define BTTV_TVBOOSTAR     0x0c
-#define BTTV_WINCAM        0x0d
-#define BTTV_MAXI          0x0e
-#define BTTV_VHX           0x10
-#define BTTV_PXC200        0x11
-#define BTTV_AVERMEDIA98   0x12
-#define BTTV_FLYVIDEO98    0x13
-
-#define BTTV_PIXVIEWPLAYTV 0x17
-#define BTTV_WINVIEW_601   0x18
-#define BTTV_CONFERENCETV  0x1c
-#endif
 
 
 #define AUDIO_TUNER        0x00
diff -u --recursive --new-file v2.3.38/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c
--- v2.3.38/linux/drivers/char/msp3400.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/char/msp3400.c	Sat Jan  8 12:54:54 2000
@@ -6,7 +6,8 @@
  * what works and what doesn't:
  *
  *  AM-Mono
- *      probably doesn't (untested)
+ *      Support for Hauppauge cards added (decoding handled by tuner) added by
+ *      Frederic Crozat <fcrozat@mail.dotcom.fr>
  *
  *  FM-Mono
  *      should work. The stereo modes are backward compatible to FM-mono,
@@ -19,7 +20,7 @@
  *      should work, no autodetect (i.e. default is mono, but you can
  *      switch to stereo -- untested)
  *
- *  NICAM (B/G, used in UK, Scandinavia and Spain)
+ *  NICAM (B/G, L , used in UK, Scandinavia, Spain and France)
  *      should work, with autodetect. Support for NICAM was added by
  *      Pekka Pietikainen <pp@netppl.fi>
  *
@@ -49,15 +50,13 @@
 #include <asm/pgtable.h>
 #include <linux/smp_lock.h>
 #endif
-
 /* kernel_thread */
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
 
 #include "audiochip.h"
-  
-#define WAIT_QUEUE                 wait_queue_head_t
 
+#define WAIT_QUEUE                 wait_queue_head_t
 
 /* sound mixer stuff */ 
 #include <linux/config.h>
@@ -278,7 +277,7 @@
 	/* NICAM/AM -- L (6.5/5.85) */
 	{ {  -2, -8, -10, 10, 50, 86 }, {  -4, -12, -9, 23, 79, 126 },
 	  MSP_CARRIER(6.5), MSP_CARRIER(6.5),
-	  0x00c6, 0x0140,   0x0120, 0x7000},
+	  0x00c6, 0x0140,   0x0120, 0x7c03},
 };
 
 struct CARRIER_DETECT {
@@ -302,7 +301,7 @@
 
 static struct CARRIER_DETECT carrier_detect_65[] = {
 	/* PAL SAT / SECAM */
-	{ MSP_CARRIER(5.85),       "5.85  PAL D/K NICAM" },
+	{ MSP_CARRIER(5.85),       "5.85  PAL D/K + SECAM NICAM" },
 	{ MSP_CARRIER(6.2578125),  "6.25  PAL D/K1 FM-stereo" },
 	{ MSP_CARRIER(6.7421875),  "6.74  PAL D/K2 FM-stereo" },
 	{ MSP_CARRIER(7.02),       "7.02  PAL SAT FM-stereo s/b" },
@@ -409,7 +408,7 @@
 
 	if (msp->nicam) {
 		/* nicam prescale */
-		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x3000);
+		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
 	}
 }
 
@@ -475,10 +474,22 @@
 	case VIDEO_SOUND_STEREO:
 		src = 0x0020 | nicam;
 #if 0 
+		/* spatial effect */
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000);
 #endif
 		break;
 	case VIDEO_SOUND_MONO:
+		if (msp->mode == MSP_MODE_AM_NICAM) {
+			printk("msp3400: switching to AM mono\n");
+			/* AM mono decoding is handled by tuner, not MSP chip */
+			/* so let's redirect sound from tuner via SCART */
+			/* volume prescale for SCART */
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
+			/* SCART switching control register*/
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, 0xe900);
+			src = 0x0200;
+			break;
+		}
 	case VIDEO_SOUND_LANG1:
 		src = 0x0000 | nicam;
 		break;
@@ -551,7 +562,7 @@
 		val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
 		if (val > 32768)
 			val -= 65536;
-		dprintk("msp3400: stereo detect register: %d\n",val);
+		dprintk("msp34xx: stereo detect register: %d\n",val);
 		
 		if (val > 4096) {
 			newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO;
@@ -566,7 +577,7 @@
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
 		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
-		dprintk("msp3400: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1);
+		dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1);
 
 		if (val & 1) {
 			/* nicam synced */
@@ -592,30 +603,33 @@
 			}
 			newnicam=1;
 		} else {
-			newnicam=0;
-#if 0 /* fixme: quick & dirty for testing */
-			if (msp->main == MSP_CARRIER(6.5)) {
-				/* This is a french mono channel => AM */
-				printk("msp3400: switching to AM mono\n");
-				msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
-				msp->second = msp->main;
-				msp3400c_setmode(msp, MSP_MODE_AM_DETECT);
-				msp3400c_setcarrier(client, msp->second, msp->main);
-			}
-#endif
+			newnicam = 0;
 			newstereo = VIDEO_SOUND_MONO;
 		}
 		break;
+	case MSP_MODE_BTSC:
+		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
+		dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+			val,
+			(val & 0x0002) ? "no"     : "yes",
+			(val & 0x0004) ? "no"     : "yes",
+			(val & 0x0040) ? "stereo" : "mono",
+			(val & 0x0080) ? ", nicam 2nd mono" : "",
+			(val & 0x0100) ? ", bilingual/SAP"  : "");
+		newstereo = VIDEO_SOUND_MONO;
+		if (val & 0x0040) newstereo |= VIDEO_SOUND_STEREO;
+		if (val & 0x0100) newstereo |= VIDEO_SOUND_LANG1;
+		break;
 	}
 	if (newstereo != msp->stereo) {
 		update = 1;
-		dprintk("msp3400: watch: stereo %d => %d\n",
+		dprintk("msp34xx: watch: stereo %d => %d\n",
 			msp->stereo,newstereo);
 		msp->stereo   = newstereo;
 	}
 	if (newnicam != msp->nicam_on) {
 		update = 1;
-		dprintk("msp3400: watch: nicam %d => %d\n",
+		dprintk("msp34xx: watch: nicam %d => %d\n",
 			msp->nicam_on,newnicam);
 		msp->nicam_on = newnicam;
 	}
@@ -706,8 +720,15 @@
 			msp->active = 0;
 			continue;
 		}
-	
+
+		/* some time for the tuner to sync */
+		current->state   = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+		if (signal_pending(current))
+			goto done;
+		
 	restart:
+		msp->restart = 0;
 		msp3400c_setvolume(client, 0, 0);
 		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
 		val1 = val2 = 0;
@@ -717,6 +738,14 @@
 
 		/* carrier detect pass #1 -- main carrier */
 		cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+
+		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
+			/* autodetect doesn't work well with AM ... */
+			max1 = 3;
+			count = 0;
+			dprintk("msp3400: AM sound override\n");
+		}
+
 		for (this = 0; this < count; this++) {
 			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
 
@@ -724,23 +753,15 @@
 			schedule_timeout(HZ/25);
 			if (signal_pending(current))
 				goto done;
-			if (msp->restart) {
+			if (msp->restart)
 				msp->restart = 0;
-				goto restart;
-			}
 
 			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
 			if (val1 < val)
 				val1 = val, max1 = this;
 			dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
 		}
-
-		if (amsound) {
-			/* autodetect does'nt work well with AM ... */
-			max1 = 3;
-			dprintk("msp3400: AM sound override\n");
-		}
-		
+	
 		/* carrier detect pass #2 -- second (stereo) carrier */
 		switch (max1) {
 		case 1: /* 5.5 */
@@ -755,6 +776,11 @@
 			cd = NULL; count = 0;
 			break;
 		}
+		
+		if (amsound && (msp->norm == VIDEO_MODE_SECAM)) {
+			/* autodetect doesn't work well with AM ... */
+			cd = NULL; count = 0; max2 = 0;
+		}
 		for (this = 0; this < count; this++) {
 			msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo);
 
@@ -762,10 +788,8 @@
 			schedule_timeout(HZ/25);
 			if (signal_pending(current))
 				goto done;
-			if (msp->restart) {
-				msp->restart = 0;
+			if (msp->restart)
 				goto restart;
-			}
 
 			val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b);
 			if (val2 < val)
@@ -811,12 +835,13 @@
 				msp->nicam_on = 0;
 				msp3400c_setstereo(client, VIDEO_SOUND_MONO);
 				msp->watch_stereo = 1;
-			} else if (max2 == 0 && msp->nicam &&
+			} else if (max2 == 0 &&
 				   msp->norm == VIDEO_MODE_SECAM) {
-				/* L NICAM */
+				/* L NICAM or AM-mono */
 				msp->second = carrier_detect_65[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_AM_NICAM);
-				msp->nicam_on = 1;
+				msp->nicam_on = 0;
+				msp3400c_setstereo(client, VIDEO_SOUND_MONO);
 				msp3400c_setcarrier(client, msp->second, msp->main);
 				msp->watch_stereo = 1;
 			} else if (max2 == 0 && msp->nicam) {
@@ -942,24 +967,19 @@
 		msp->active = 1;
 
 		if (msp->watch_stereo) {
-#if 1 /* dump status register */
-			val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
-			printk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
-			       val,
-			       (val & 0x0002) ? "no"     : "yes",
-			       (val & 0x0004) ? "no"     : "yes",
-			       (val & 0x0040) ? "stereo" : "mono",
-			       (val & 0x0080) ? ", nicam 2nd mono" : "",
-			       (val & 0x0100) ? ", bilingual/SAP"  : "");
-			msp->watch_stereo = 0;
-#else
-			watch_stereo(msp);
-#endif
+			watch_stereo(client);
 			msp->active = 0;
 			continue;
 		}
 	
+		/* some time for the tuner to sync */
+		current->state   = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+		if (signal_pending(current))
+			goto done;
+
 	restart:
+		msp->restart = 0;
 		del_timer(&msp->wake_stereo);
 		msp->watch_stereo = 0;
 
@@ -977,6 +997,9 @@
 			std  = 0x0020;
 			break;
 		case VIDEO_MODE_SECAM: 
+			mode = 0x0003;
+			std = 1;
+			break;
 		default:
 			mode = 0x0003;
 			std  = 1;
@@ -1005,10 +1028,8 @@
 				schedule_timeout(HZ/10);
 				if (signal_pending(current))
 					goto done;
-				if (msp->restart) {
-					msp->restart = 0;
+				if (msp->restart)
 					goto restart;
-				}
 
 				/* check results */
 				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
@@ -1027,11 +1048,21 @@
 		msp->main   = modelist[i].main;
 		msp->second = modelist[i].second;
 
+		if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
+			/* autodetection has failed, let backup */
+			dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n",
+				modelist[8].name ? modelist[8].name : "unknown",val);
+			val = 0x0009;
+			msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
+		}
+
 		/* set prescale / stereo */
 		switch (val) {
-		case 0x0009:
-			msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x7c03); /* AM */
-			msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */
+		case 0x0009:			
+			msp->mode = MSP_MODE_AM_NICAM;
+			msp->stereo = VIDEO_SOUND_MONO;
+			msp3400c_setstereo(client,VIDEO_SOUND_MONO);
+			msp->watch_stereo = 1;
 			break;
 		case 0x0020: /* BTSC */
 			/* just turn on stereo */
@@ -1479,12 +1510,8 @@
 		va->bass = msp->bass;
 		va->treble = msp->treble;
 
-		if (msp->simple) {
-			/* fixme */
-		} else {
-			autodetect_stereo(client);
-			va->mode = msp->stereo;
-		}
+		autodetect_stereo(client);
+		va->mode = msp->stereo;
 		break;
 	}
 	case VIDIOCSAUDIO:
@@ -1501,9 +1528,7 @@
 		msp3400c_setbass(client,msp->bass);
 		msp3400c_settreble(client,msp->treble);
 
-		if (msp->simple) {
-			/* fixme */
-		} else if (va->mode != 0) {
+		if (va->mode != 0) {
 			msp->watch_stereo=0;
 			del_timer(&msp->wake_stereo);
 			msp->stereo = va->mode;
@@ -1584,17 +1609,11 @@
 		msp3400c_settreble(client,msp->treble);
 		break;
 
-	case AUDC_GET_STEREO:
-		if (msp->simple) {
-			*sarg = 0; /* fixme */
-		} else {
-			autodetect_stereo(client);
-			*sarg = msp->stereo;
-		}
+	case AUDC_GET_STEREO:	
+	        autodetect_stereo(client);
+	        *sarg = msp->stereo;		
 		break;
 	case AUDC_SET_STEREO:
-		if (msp->simple)
-			break; /* fixme */
 		if (*sarg) {
 			msp->watch_stereo=0;
 			del_timer(&msp->wake_stereo);
@@ -1642,4 +1661,3 @@
  * c-basic-offset: 8
  * End:
  */
-
diff -u --recursive --new-file v2.3.38/linux/drivers/char/stradis.c linux/drivers/char/stradis.c
--- v2.3.38/linux/drivers/char/stradis.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/char/stradis.c	Sat Jan  8 12:54:54 2000
@@ -2249,7 +2249,7 @@
 	saa_num = 0;
 
 	while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) {
-		if (!dev->subsystem_vendor_id)
+		if (!dev->subsystem_vendor)
 			printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num);
 		else
 			printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); 
diff -u --recursive --new-file v2.3.38/linux/drivers/char/tda8425.c linux/drivers/char/tda8425.c
--- v2.3.38/linux/drivers/char/tda8425.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/char/tda8425.c	Sat Jan  8 12:54:54 2000
@@ -104,7 +104,7 @@
 	tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0);
 }
 
-static void tda8425_init(struct i2c_client *client)
+static void do_tda8425_init(struct i2c_client *client)
 {
 	struct tda8425 *tda = client->data;
 
@@ -152,7 +152,7 @@
 	if (!tda)
 		return -ENOMEM;
 	memset(tda,0,sizeof *tda);
-	tda8425_init(client);
+	do_tda8425_init(client);
 	MOD_INC_USE_COUNT;
 	strcpy(client->name,"TDA8425");
 	printk(KERN_INFO "tda8425: init\n");
@@ -173,7 +173,7 @@
 {
 	struct tda8425 *tda  = client->data;
     
-	tda8425_init(client);
+	do_tda8425_init(client);
 	i2c_detach_client(client);
 
 	kfree(tda);
diff -u --recursive --new-file v2.3.38/linux/drivers/char/tda9855.c linux/drivers/char/tda9855.c
--- v2.3.38/linux/drivers/char/tda9855.c	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/tda9855.c	Sat Jan  8 12:54:54 2000
@@ -194,7 +194,7 @@
 	return 0;
 }
 
-static void tda9855_init(struct i2c_client *client)
+static void do_tda9855_init(struct i2c_client *client)
 {
 	struct tda9855 *t = client->data;
 
@@ -235,7 +235,7 @@
 	if (!t)
 		return -ENOMEM;
 	memset(t,0,sizeof *t);
-	tda9855_init(client);
+	do_tda9855_init(client);
 	MOD_INC_USE_COUNT;
 	strcpy(client->name,"TDA9855");
 	printk(KERN_INFO "tda9855: init\n");
@@ -255,7 +255,7 @@
 {
 	struct tda9855 *t  = client->data;
 
-	tda9855_init(client);
+	do_tda9855_init(client);
 	i2c_detach_client(client);
 	
 	kfree(t);
@@ -298,8 +298,7 @@
 
 		va->mode = ((TDA9855_STP | TDA9855_SAPP) & 
 			    tda9855_read(client)) >> 4;
-		if (0 == va->mode)
-			va->mode = VIDEO_SOUND_MONO;
+		va->mode |= VIDEO_SOUND_MONO;
 		break;
 	}
 	case VIDIOCSAUDIO:
@@ -327,7 +326,7 @@
 		case VIDEO_SOUND_STEREO:
 			t->c2= TDA9855_STEREO | (t->c2 & 0x3f); 
 			break;
-		case VIDEO_SOUND_LANG2:
+		case VIDEO_SOUND_LANG1:
 			t->c2= TDA9855_SAP | (t->c2 & 0x3f); 
 			break;
 		}
@@ -445,7 +444,7 @@
 #ifdef MODULE
 void cleanup_module(void)
 {
-	i2c_add_driver(&driver);
+	i2c_del_driver(&driver);
 }
 #endif
 
diff -u --recursive --new-file v2.3.38/linux/drivers/char/tea6300.c linux/drivers/char/tea6300.c
--- v2.3.38/linux/drivers/char/tea6300.c	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/tea6300.c	Sat Jan  8 12:54:54 2000
@@ -111,7 +111,7 @@
 	tea6300_write(client, TEA6300_TR, tea->treble>>12);
 }
 
-static void tea6300_init(struct i2c_client *client)
+static void do_tea6300_init(struct i2c_client *client)
 {
 	struct tea6300 *tea = client->data;
 	
@@ -173,7 +173,7 @@
 	if (!tea)
 		return -ENOMEM;
 	memset(tea,0,sizeof *tea);
-	tea6300_init(client);
+	do_tea6300_init(client);
 
 	MOD_INC_USE_COUNT;
 	strcpy(client->name,"TEA6300T");
@@ -194,7 +194,7 @@
 {
 	struct tea6300 *tea  = client->data;
     
-	tea6300_init(client);
+	do_tea6300_init(client);
 	i2c_detach_client(client);
 
 	kfree(tea);
diff -u --recursive --new-file v2.3.38/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.3.38/linux/drivers/i2o/i2o_block.c	Fri Jan  7 19:13:21 2000
+++ linux/drivers/i2o/i2o_block.c	Sat Jan  8 17:41:16 2000
@@ -685,7 +685,6 @@
 	minor = MINOR(inode->i_rdev);
 	if (minor >= (MAX_I2OB<<4))
 		return -ENODEV;
-	sync_dev(inode->i_rdev);
 	dev = &i2ob_dev[(minor&0xF0)];
 	if (dev->refcnt <= 0)
 		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
diff -u --recursive --new-file v2.3.38/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.3.38/linux/drivers/i2o/i2o_config.c	Thu Nov 11 20:11:34 1999
+++ linux/drivers/i2o/i2o_config.c	Mon Jan 10 14:05:32 2000
@@ -1,26 +1,28 @@
 /*
- *	I2O Configuration Interface Driver
+ * I2O Configuration Interface Driver
  *
- *	(C) Copyright 1999   Red Hat Software
+ * (C) Copyright 1999   Red Hat Software
  *	
- *	Written by Alan Cox, Building Number Three Ltd
+ * Written by Alan Cox, Building Number Three Ltd
  *
- *      Modified 04/20/1999 by Deepak Saxena
- *         - Added basic ioctl() support
- *      Modified 06/07/1999 by Deepak Saxena
- *         - Added software download ioctl (still testing)
- *	Modified 09/10/1999 by Auvo Häkkinen
- *	   - Changes to i2o_cfg_reply(), ioctl_parms()
- *	   - Added ioct_validate()
- *	Modified 09/30/1999 by Taneli Vähäkangas
- *	   - Fixed ioctl_swdl()
- *	Modified 10/04/1999 by Taneli Vähäkangas
- *	   - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
+ * Modified 04/20/1999 by Deepak Saxena
+ *   - Added basic ioctl() support
+ * Modified 06/07/1999 by Deepak Saxena
+ *   - Added software download ioctl (still testing)
+ * Modified 09/10/1999 by Auvo Häkkinen
+ *   - Changes to i2o_cfg_reply(), ioctl_parms()
+ *   - Added ioct_validate()
+ * Modified 09/30/1999 by Taneli Vähäkangas
+ *   - Fixed ioctl_swdl()
+ * Modified 10/04/1999 by Taneli Vähäkangas
+ *   - Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
+ * Modified 11/18/199 by Deepak Saxena
+ *   - Added event managmenet support
  *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- * 	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
+ * 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/module.h>
@@ -37,13 +39,29 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-static int i2o_cfg_token = 0;
 static int i2o_cfg_context = -1;
 static void *page_buf;
 static void *i2o_buffer;
 static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED;
 struct wait_queue *i2o_wait_queue;
 
+#define MODINC(x,y) (x = x++ % y)
+
+struct i2o_cfg_info
+{
+	struct file* fp;
+	struct fasync_struct *fasync;
+	struct i2o_evt_info event_q[I2O_EVT_Q_LEN];
+	u16		q_in;		// Queue head index
+	u16		q_out;		// Queue tail index
+	u16		q_len;		// Queue length
+	u16		q_lost;		// Number of lost events
+	u32		q_id;		// Event queue ID...used as tx_context
+	struct	i2o_cfg_info *next;
+};
+static struct i2o_cfg_info *open_files = NULL;
+static int i2o_cfg_info_id = 0;
+
 static int ioctl_getiops(unsigned long);
 static int ioctl_gethrt(unsigned long);
 static int ioctl_getlct(unsigned long);
@@ -53,6 +71,9 @@
 static int ioctl_swul(unsigned long);
 static int ioctl_swdel(unsigned long);
 static int ioctl_validate(unsigned long); 
+static int ioctl_evt_reg(unsigned long, struct file *);
+static int ioctl_evt_get(unsigned long, struct file *);
+static int cfg_fasync(int, struct file*, int);
 
 /*
  *	This is the callback for any message we have posted. The message itself
@@ -62,13 +83,78 @@
  */
 static void i2o_cfg_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m)
 {
-        u32 *msg = (u32 *)m;
+	u32 *msg = (u32 *)m;
+
+	if (msg[0] & (1<<13))
+		printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
         
-	if (msg[4] >> 24) // RegStatus != SUCCESS
-        	i2o_cfg_token = -(msg[4] & 0xFFFF); // DetailedStatus
-        else
-		i2o_cfg_token = I2O_POST_WAIT_OK;
-               
+	if (msg[4] >> 24)  // RegStatus != SUCCESS
+		i2o_report_status(KERN_INFO,"i2o_config",msg);
+
+	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)
+	{
+		struct i2o_cfg_info *inf;
+
+		for(inf = open_files; inf; inf = inf->next)
+			if(inf->q_id == msg[3])
+				break;
+
+		//
+		// If this is the case, it means that we're getting
+		// events for a file descriptor that's been close()'d
+		// w/o the user unregistering for events first.
+		// The code currently assumes that the user will 
+		// take care of unregistering for events before closing
+		// a file.
+		// 
+		// TODO: 
+		// Should we track event registartion and deregister
+		// for events when a file is close()'d so this doesn't
+		// happen? That would get rid of the search through
+		// the linked list since file->private_data could point
+		// directly to the i2o_config_info data structure...but
+		// it would mean having all sorts of tables to track
+		// what each file is registered for...I think the
+		// current method is simpler. - DS
+		//			
+		if(!inf)
+			return;
+
+		inf->event_q[inf->q_in].id.iop = c->unit;
+		inf->event_q[inf->q_in].id.tid = m->target_tid;
+		inf->event_q[inf->q_in].id.evt_mask = msg[4];
+
+		//
+		// Data size = msg size - reply header
+		//
+		inf->event_q[inf->q_in].data_size = (m->size - 5) * 4;
+		if(inf->event_q[inf->q_in].data_size)
+			memcpy(inf->event_q[inf->q_in].evt_data, 
+				(unsigned char *)(msg + 5),
+				inf->event_q[inf->q_in].data_size);
+
+		spin_lock(&i2o_config_lock);
+		MODINC(inf->q_in, I2O_EVT_Q_LEN);
+		if(inf->q_len == I2O_EVT_Q_LEN)
+		{
+			MODINC(inf->q_out, I2O_EVT_Q_LEN);
+			inf->q_lost++;
+		}
+		else
+		{
+			// Keep I2OEVTGET on another CPU from touching this
+			inf->q_len++;
+		}
+		spin_unlock(&i2o_config_lock);
+		
+
+//		printk(KERN_INFO "File %p w/id %d has %d events\n",
+//			inf->fp, inf->q_id, inf->q_len);	
+
+		if(inf->fasync)
+			kill_fasync(inf->fasync, SIGIO, POLL_IN);
+	}
+
 	return;
 }
 
@@ -107,14 +193,11 @@
 /*
  * IOCTL Handler
  */
-static int cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+static int cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
 	unsigned long arg)
 {
 	int ret;
 
-	/* Only 1 token, so lock... */
-	spin_lock(&i2o_config_lock);
-
 	switch(cmd)
 	{	
 		case I2OGETIOPS:
@@ -157,11 +240,18 @@
 			ret = ioctl_html(arg);
 			break;
 
+		case I2OEVTREG:
+			ret = ioctl_evt_reg(arg, fp);
+			break;
+
+		case I2OEVTGET:
+			ret = ioctl_evt_get(arg, fp);
+			break;
+
 		default:
 			ret = -EINVAL;
 	}
 
-	spin_unlock(&i2o_config_lock);
 	return ret;
 }
 
@@ -320,7 +410,7 @@
 	}
 
         len = i2o_issue_params(i2o_cmd, c, kcmd.tid, 
-       			ops, kcmd.oplen, res, sizeof(res));
+       			ops, kcmd.oplen, res, 65536);
         i2o_unlock_controller(c);
 	kfree(ops);
         
@@ -392,7 +482,7 @@
 		}
 	}
 
-	res = kmalloc(4096, GFP_KERNEL);
+	res = kmalloc(65536, GFP_KERNEL);
 	if(!res)
 	{
 		i2o_unlock_controller(c);
@@ -403,21 +493,22 @@
 	msg[2] = i2o_cfg_context;
 	msg[3] = 0;
 	msg[4] = kcmd.page;
-	msg[5] = 0xD0000000|4096;
+	msg[5] = 0xD0000000|65536;
 	msg[6] = virt_to_bus(res);
 	if(!kcmd.qlen) /* Check for post data */
 		msg[0] = SEVEN_WORD_MSG_SIZE|SGL_OFFSET_5;
 	else
 	{
 		msg[0] = NINE_WORD_MSG_SIZE|SGL_OFFSET_5;
-		msg[5] = 0x50000000|4096;
+		msg[5] = 0x50000000|65536;
 		msg[7] = 0xD4000000|(kcmd.qlen);
 		msg[8] = virt_to_phys(query);
 	}
 
 	token = i2o_post_wait(c, msg, 9*4, 10);
-	if(token != I2O_POST_WAIT_OK)
+	if(token)
 	{
+		printk(KERN_DEBUG "token = %#10x\n", token);
 		i2o_unlock_controller(c);
 		kfree(res);
 		if(kcmd.qlen) kfree(query);
@@ -426,7 +517,7 @@
 	}
 	i2o_unlock_controller(c);
 
-	len = strnlen(res, 8192);
+	len = strnlen(res, 65536);
 	put_user(len, kcmd.reslen);
 	if(len > reslen)
 		ret = -ENOMEM;
@@ -500,7 +591,7 @@
 	{
 		// it fails if you try and send frags out of order
 		// and for some yet unknown reasons too
-		printk("i2o_config: swdl failed, DetailedStatus = %d\n", status);
+		printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status);
 		return -ETIMEDOUT;
 	}
 
@@ -562,7 +653,7 @@
 	if (status != I2O_POST_WAIT_OK)
 	{
 		kfree(buffer);
-		printk("i2o_config: swul failed, DetailedStatus = %d\n", status);
+		printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status);
 		return -ETIMEDOUT;
 	}
 	
@@ -603,7 +694,7 @@
 	
 	if (token != I2O_POST_WAIT_OK)
 	{
-		printk("i2o_config: swdel failed, DetailedStatus = %d\n", token);
+		printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token);
 		return -ETIMEDOUT;
 	}
 	
@@ -631,7 +722,7 @@
 
         if (token != I2O_POST_WAIT_OK)
         {
-                printk("Can't validate configuration, ErrorStatus = %d\n",
+                printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n",
                 	token);
                 return -ETIMEDOUT;
         }
@@ -639,22 +730,154 @@
         return 0;
 }   
 
+static int ioctl_evt_reg(unsigned long arg, struct file *fp)
+{
+	u32 msg[5];
+	struct i2o_evt_id *pdesc = (struct i2o_evt_id *)arg;
+	struct i2o_evt_id kdesc;
+	struct i2o_controller *iop;
+	struct i2o_device *d;
+
+	if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))
+		return -EFAULT;
+
+	/* IOP exists? */
+	iop = i2o_find_controller(kdesc.iop);
+	if(!iop)
+		return -ENXIO;
+	i2o_unlock_controller(iop);
+
+	/* Device exists? */
+	for(d = iop->devices; d; d = d->next)
+		if(d->lct_data->tid == kdesc.tid)
+			break;
+
+	if(!d)
+		return -ENODEV;
+
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid;
+	msg[2] = (u32)i2o_cfg_context;
+	msg[3] = (u32)fp->private_data;
+	msg[4] = kdesc.evt_mask;
+
+	i2o_post_this(iop, msg, 20);
+
+	return 0;
+}	
+
+static int ioctl_evt_get(unsigned long arg, struct file *fp)
+{
+	u32 id = (u32)fp->private_data;
+	struct i2o_cfg_info *p = NULL;
+	struct i2o_evt_get *uget = (struct i2o_evt_get*)arg;
+	struct i2o_evt_get kget;
+	unsigned int flags;
+
+	// access_ok doesn't check for NULL?!?!
+	if(!arg)
+		return -EFAULT;
+	
+	if(!access_ok(VERIFY_WRITE, uget,  sizeof(struct i2o_evt_get)))
+		return -EFAULT;
+
+	for(p = open_files; p; p = p->next)
+		if(p->q_id == id)
+			break;
+
+	if(!p->q_len)
+	{
+		return -ENOENT;
+		return 0;
+	}
+
+	memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info));
+	MODINC(p->q_out, I2O_EVT_Q_LEN);
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	p->q_len--;
+	kget.pending = p->q_len;
+	kget.lost = p->q_lost;
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+
+	__copy_to_user(uget, &kget, sizeof(struct i2o_evt_get));
+
+	return 0;
+}
 
 static int cfg_open(struct inode *inode, struct file *file)
 {
-	/* 
-         * Should support multiple management users
-         */
+	struct i2o_cfg_info *tmp = 
+		(struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL);
+	unsigned int flags;
+
+	if(!tmp)
+		return -ENOMEM;
+
+	file->private_data = (void*)(i2o_cfg_info_id++);
+	tmp->fp = file;
+	tmp->fasync = NULL;
+	tmp->q_id = (u32)file->private_data;
+	tmp->q_len = 0;
+	tmp->q_in = 0;
+	tmp->q_out = 0;
+	tmp->q_lost = 0;
+	tmp->next = open_files;
+
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	open_files = tmp;
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+	
 	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int cfg_release(struct inode *inode, struct file *file)
 {
+	u32 id = (u32)file->private_data;
+	struct i2o_cfg_info *p1, *p2;
+	unsigned int flags;
+
+	p1 = p2 = NULL;
+
+	spin_lock_irqsave(&i2o_config_lock, flags);
+	for(p1 = open_files; p1; )
+	{
+		if(p1->q_id == id)
+		{
+
+			if(p1->fasync)
+				cfg_fasync(-1, file, 0);
+			if(p2)
+				p2->next = p1->next;
+			else
+				open_files = p1->next;
+
+			kfree(p1);
+			break;
+		}
+		p2 = p1;
+		p1 = p1->next;
+	}
+	spin_unlock_irqrestore(&i2o_config_lock, flags);
+
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+static int cfg_fasync(int fd, struct file *fp, int on)
+{
+	u32 id = (u32)fp->private_data;
+	struct i2o_cfg_info *p;
+
+	for(p = open_files; p; p = p->next)
+		if(p->q_id == id)
+			break;
+
+	if(!p)
+		return -EBADF;
+
+	return fasync_helper(fd, fp, on, &p->fasync);
+}
 
 static struct file_operations config_fops =
 {
@@ -667,7 +890,9 @@
 	NULL,		/* No mmap */
 	cfg_open,
 	NULL,		/* No flush */
-	cfg_release
+	cfg_release,
+	NULL,
+	cfg_fasync
 };
 
 static struct miscdevice i2o_miscdev = {
@@ -682,7 +907,8 @@
 int __init i2o_config_init(void)
 #endif
 {
-	printk(KERN_INFO "i2o configuration manager v 0.03\n");
+	printk(KERN_INFO "I2O configuration manager v 0.04.\n");
+	printk(KERN_INFO "  (C) Copyright 1999 Red Hat Software");
 	
 	if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL)
 	{
diff -u --recursive --new-file v2.3.38/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.38/linux/drivers/i2o/i2o_core.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/i2o/i2o_core.c	Mon Jan 10 14:05:32 2000
@@ -18,7 +18,6 @@
  *		Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI> 
  *		Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI> 
  *		Deepak Saxena <deepak@plexity.net> 
- * 
  */
 
 #include <linux/config.h>
@@ -35,7 +34,6 @@
 
 #include <linux/bitops.h>
 #include <linux/wait.h>
-#include <linux/delay.h>
 #include <linux/timer.h>
 
 #include <asm/io.h>
@@ -53,19 +51,22 @@
  
 static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];
 static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];
+struct i2o_controller *i2o_controller_chain;
 int i2o_num_controllers = 0;
 static int core_context = 0;
 
-extern int i2o_online_controller(struct i2o_controller *c);
+static int i2o_activate_controller(struct i2o_controller *iop);
+static int i2o_online_controller(struct i2o_controller *c);
 static int i2o_init_outbound_q(struct i2o_controller *c);
 static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,
 			   struct i2o_message *);
 static int i2o_add_management_user(struct i2o_device *, struct i2o_handler *);
 static int i2o_remove_management_user(struct i2o_device *, struct i2o_handler *);
-static void i2o_dump_message(u32 *msg);
+void i2o_dump_message(u32 *msg);
 
 static int i2o_issue_claim(struct i2o_controller *, int, int, int, u32);
 
+static int i2o_reset_controller(struct i2o_controller *);
 static int i2o_lct_get(struct i2o_controller *);
 static int i2o_hrt_get(struct i2o_controller *);
 
@@ -176,9 +177,7 @@
 	{
 		if (msg[4] >> 24)
 		{
-			/* 0x40000000 is used as an error report supress bit */
-			if(msg[2]&0x40000000)
-				i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
+			i2o_report_status(KERN_WARNING, "i2o_core: post_wait reply", msg);
 			status = -(msg[4] & 0xFFFF);
 		}
 		else
@@ -233,7 +232,6 @@
 	d->next=c->devices;
 	c->devices=d;
 	*d->dev_name = 0;
-	d->owner = NULL;
 
 	for(i = 0; i < I2O_MAX_MANAGERS; i++)
 		d->managers[i] = NULL;
@@ -307,12 +305,7 @@
 			c->next=i2o_controller_chain;
 			i2o_controller_chain=c;
 			c->unit = i;
-			c->page_frame = NULL;
-			c->hrt = NULL;
-			c->lct = NULL;
-			c->status_block = NULL;
-//			printk(KERN_INFO "lct @ %p hrt @ %p status @ %p",
-//					c->lct, c->hrt, c->status_block);
+
 			sprintf(c->name, "i2o/iop%d", i);
 			i2o_num_controllers++;
 			spin_unlock(&i2o_configuration_lock);
@@ -328,15 +321,13 @@
 {
 	struct i2o_controller **p;
 	int users;
-
-#ifdef DRIVERDEBUG
-	printk(KERN_INFO "Deleting controller iop%d\n", c->unit);
-#endif
+	char name[16];
 
 	spin_lock(&i2o_configuration_lock);
 	if((users=atomic_read(&c->users)))
 	{
-		printk(KERN_INFO "I2O: %d users for controller iop%d\n", users, c->unit);
+		printk(KERN_INFO "%s busy: %d users for controller.\n", c->name, users);
+		c->bus_disable(c); 
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
 	}
@@ -345,6 +336,7 @@
 		if(__i2o_delete_device(c->devices)<0)
 		{
 			/* Shouldnt happen */
+			c->bus_disable(c); 
 			spin_unlock(&i2o_configuration_lock);
 			return -EBUSY;
 		}
@@ -356,8 +348,8 @@
 	{
 		if(*p==c)
 		{
-			/* Ask the IOP to switch to HOLD state */
-			i2o_clear_controller(c);
+			/* Ask the IOP to switch into RESET state */
+			i2o_reset_controller(c);
 
 			/* Release IRQ */
 			c->destructor(c);
@@ -365,8 +357,6 @@
 			*p=c->next;
 			spin_unlock(&i2o_configuration_lock);
 
-//			printk(KERN_INFO "hrt %p lct %p page_frame %p status_block %p\n",
-//				c->hrt, c->lct, c->page_frame, c->status_block);
 			if(c->page_frame)
 				kfree(c->page_frame);
 			if(c->hrt)
@@ -376,14 +366,13 @@
 			if(c->status_block)
 				kfree(c->status_block);
 
-			kfree(c);
-
 			i2o_controllers[c->unit]=NULL;
-
+			memcpy(name, c->name, strlen(c->name)+1);
+			kfree(c);
 			i2o_num_controllers--;
-#ifdef DRIVERDEBUG
-			printk(KERN_INFO "iop deleted\n");
-#endif
+			
+			dprintk((KERN_INFO "%s: Deleted from controller chain.\n", name));
+
 			return 0;
 		}
 		p=&((*p)->next);
@@ -540,17 +529,20 @@
 	u32 mv;
 
 #ifdef DEBUG_IRQ
-	printk(KERN_INFO "iop%d interrupt\n", c->unit);
+	printk(KERN_INFO "%s: interrupt\n", c->name);
 #endif
+	/* Sometimes we get here, but a message can't be read. Why? */
+	if((mv=I2O_REPLY_READ32(c))==0xFFFFFFFF)
+		mv=I2O_REPLY_READ32(c);
 
-	while((mv=I2O_REPLY_READ32(c))!=0xFFFFFFFF)
+	while (mv!=0xFFFFFFFF)
 	{
 		struct i2o_handler *i;
 		m=(struct i2o_message *)bus_to_virt(mv);
 		/*
 		 *	Temporary Debugging
 		 */
-		if(((m->function_addr>>24)&0xFF)==0x15)
+		if(m->function==0x15)
 			printk("UTFR!\n");
 
 #ifdef DEBUG_IRQ
@@ -562,12 +554,13 @@
 			i->reply(i,c,m);
 		else
 		{
-			printk("Spurious reply to handler %d\n", 
+			printk("i2o: Spurious reply to handler %d\n", 
 				m->initiator_context&(MAX_I2O_MODULES-1));
 			i2o_dump_message((u32*)m);
 		}	
 	 	i2o_flush_reply(c,mv);
 		mb();
+		mv=I2O_REPLY_READ32(c);
 	}
 }
 
@@ -699,7 +692,6 @@
 	}
 	if(i2o_query_scalar(c, unit, 0xF100, 4, buf, 16)>=0)
 	{
-
 		buf[16]=0;
 		printk("     Device: %s", buf);
 	}
@@ -707,7 +699,7 @@
 	if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
 	{
 		buf[16]=0;
-		printk(KERN_INFO "Description: %s\n", buf);
+		printk("Description: %s", buf);
 	}
 #endif	
 	if(i2o_query_scalar(c, unit, 0xF100, 6, buf, 8)>=0)
@@ -831,25 +823,17 @@
 	char str[22];
 	i2o_lct *lct = c->lct;
 
-	max = lct->table_size;
+	if (lct == NULL) {
+		printk(KERN_ERR "%s: LCT is empty???\n",c->name);
+		return -1;
+	}
 	
+	max = lct->table_size;	
 	max -= 3;
 	max /= 9;
 
-	if(max==0)
-	{
-		printk(KERN_ERR "%s: LCT is empty????\n",c->name);
-		return -1;
-	}
-
 	printk(KERN_INFO "%s: LCT has %d entries.\n", c->name,max);
 	
-	if(max > 128)
-	{
-		printk(KERN_INFO "%s: LCT was truncated.\n",c->name);
-		max=128;
-	}
-	
 	if(lct->iop_flags&(1<<0))
 		printk(KERN_WARNING "%s: Configuration dialog desired.\n", c->name);
 		
@@ -870,7 +854,7 @@
 		d->flags = 0;
 		tid = d->lct_data->tid;
 		
-		printk(KERN_INFO "Task ID %d.\n", tid);
+		printk(KERN_INFO "Target ID %d.\n", tid);
 
 		i2o_report_controller_unit(c, tid);
 		
@@ -880,10 +864,10 @@
 		
 		sprintf(str, "%-21s", i2o_get_class_name(d->lct_data->class_id));
 		printk("%s", str);
-		
-		printk(" Subclass: 0x%04X                Flags: ",
+
+		printk(" Subclass: 0x%04X                Flags: ", 
 			d->lct_data->sub_class);
-			
+
 		if(d->lct_data->device_flags&(1<<0))
 			printk("C");		// ConfigDialog requested
 		if(d->lct_data->device_flags&(1<<1))
@@ -899,37 +883,44 @@
 }
 
 
-/* Quiesce IOP */
+/* 
+ * Quiesce IOP. Causes IOP to make external operation quiescend. 
+ * Internal operation of the IOP continues normally.
+ */
 int i2o_quiesce_controller(struct i2o_controller *c)
 {
 	u32 msg[4];
 	int ret;
 
-	if ((c->status_block->iop_state != ADAPTER_STATE_READY) &
-	    (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)) 
+	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+
+	if ((c->status_block->iop_state != ADAPTER_STATE_READY) &&
+	    (c->status_block->iop_state != ADAPTER_STATE_OPERATIONAL))
 	{
-		dprintk((KERN_INFO "%s: Not in READY or OPERATIONAL state\n", 
-			c->name));
-		dprintk((KERN_INFO "%s: state = %d\n", 
-			c->name, c->status_block->iop_state));
-		return -EINVAL;
+		return 0;
 	}
 
 	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
-	/* msg[2] and msg[3] filled in i2o_post_wait */
+	/* msg[2] filled in i2o_post_wait */
+	msg[3]=0;
 
 	/* Long timeout needed for quiesce if lots of devices */
 
 	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 120)))
-		printk(KERN_INFO "%s: Unable to quiesce.\n", c->name);
+		printk(KERN_INFO "%s: Unable to quiesce (status=%#10x).\n", 
+			c->name, ret);
 	else
 		dprintk((KERN_INFO "%s: Quiesced.\n", c->name));
 
+	i2o_status_get(c); // Reread the Status Block
+
 	return ret;
 }
 
-/* Enable IOP */
+/* 
+ * Enable IOP. Allows the IOP to resume external operations.
+ */
 int i2o_enable_controller(struct i2o_controller *c)
 {
 	u32 msg[4];
@@ -937,44 +928,80 @@
 	
 	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
-	/* msg[2] and msg[3] filled in i2o_post_wait */
+	/* msg[2] filled in i2o_post_wait */
 
 	/* How long of a timeout do we need? */
 
 	if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240)))
-		printk(KERN_ERR "%s: Could not enable, %d\n", c->name, ret);
+		printk(KERN_ERR "%s: Could not enable (status=%#10x).\n", 
+			c->name, ret);
+	else
+		dprintk((KERN_INFO "%s: Enabled.\n", c->name));
+
+	i2o_status_get(c);
 
 	return ret;
 }
 
-/* Reset an IOP, but keep message queues alive */
+/* 
+ * Clear an IOP to HOLD state, ie. terminate external operations, clear all 
+ * input queues and prepare for a system restart. IOP's internal operation
+ * continues normally and the outbound queue is alive.
+ * IOP is not expected to rebuild its LCT.
+ */
 int i2o_clear_controller(struct i2o_controller *c)
 {
+	struct i2o_controller *iop;
 	u32 msg[4];
 	int ret;
 
+	/* Quiesce all IOPs first */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		i2o_quiesce_controller(iop);
+
 	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_ADAPTER_CLEAR<<24|HOST_TID<<12|ADAPTER_TID;
-	/* msg[2] and msg[3] filled in i2o_post_wait */
+	/* msg[2] filled in i2o_post_wait */
+	msg[3]=0;
 
 	if ((ret=i2o_post_wait(c, msg, sizeof(msg), 30)))
-		printk(KERN_INFO "%s: Unable to clear, %#10x\n", 
+		printk(KERN_INFO "%s: Unable to clear (status=%#10x).\n", 
 			c->name, ret);
+	else
+		dprintk((KERN_INFO "%s: Cleared.\n",c->name));
 
-	i2o_status_get(c); // Reread the Status Block
+	i2o_status_get(c);
+
+	/* Enable other IOPs */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		if (iop != c)
+			i2o_enable_controller(iop);		
 
 	return ret;
 }
 
 
-/* Reset the IOP to sane state */
+/* 
+ * Reset the IOP into INIT state and wait until IOP gets into RESET state.  
+ * Terminate all external operations, clear IOP's inbound and outbound 
+ * queues, terminate all DDMs, and reload the IOP's operating environment 
+ * and all local DDMs. IOP rebuilds its LCT.
+ */
 static int i2o_reset_controller(struct i2o_controller *c)
 {
+	struct i2o_controller *iop; 
 	u32 m;
 	u8 *status;
 	u32 *msg;
 	long time;
 
+	/* Quiesce all IOPs first */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		i2o_quiesce_controller(iop);
+
 	m=i2o_wait_message(c, "AdapterReset");
 	if(m==0xFFFFFFFF)	
 		return -ETIMEDOUT;
@@ -1013,16 +1040,14 @@
 		barrier();
 	}
 
-	if (status[0]==0x02) 
-		printk(KERN_WARNING "%s: Reset rejected.\n",c->name); 
-	else 
+	if (status[0]==0x01) 
 	{
 		/* 
 		 * Once the reset is sent, the IOP goes into the INIT state 
-		 * which is inditerminate.  We need to wait until the IOP 
+		 * which is indeterminate.  We need to wait until the IOP 
 		 * has rebooted before we can let the system talk to 
 		 * it. We read the inbound Free_List until a message is 
-		 * available.  If we can't read one in the given ammount of 
+		 * available.  If we can't read one in the given amount of 
 		 * time, we assume the IOP could not reboot properly.  
 		 */ 
 
@@ -1043,9 +1068,26 @@
 		} 
 
 		i2o_flush_reply(c,m);
-		printk(KERN_INFO "%s: Reset completed.\n", c->name);
+
+		dprintk((KERN_INFO "%s: Reset completed.\n", c->name));
 	}
 
+	/* If IopReset was rejected or didn't perform reset, try IopClear */
+
+	i2o_status_get(c);
+	if (status[0] == 0x02 || c->status_block->iop_state != ADAPTER_STATE_RESET)
+	{
+		printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); 
+		i2o_clear_controller(c);
+
+	}
+
+	/* Enable other IOPs */
+
+	for (iop = i2o_controller_chain; iop; iop = iop->next)
+		if (iop != c)
+			i2o_enable_controller(iop);		
+
 	kfree(status);
 	return 0;
 }
@@ -1157,13 +1199,14 @@
 
 		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
 		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
-		/* msg[2] and msg[3] filled in i2o_post_wait */
+		/* msg[2] filled in i2o_post_wait */
+		msg[3]= 0;
 		msg[4]= (0xD0000000 | size);	/* Simple transaction */
 		msg[5]= virt_to_phys(c->hrt);	/* Dump it here */
 
 		if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
-			printk(KERN_ERR "%s: Unable to get HRT,"
-				" Status = %d.\n",c->name, ret);	
+			printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n",
+				c->name, ret);	
 			return ret;
 		}
 
@@ -1193,6 +1236,8 @@
         iop->status->current_io_base;
         iop->status->current_io_size;
 #endif
+
+/* FIXME */
         privmem[0]=iop->priv_mem;       /* Private memory space base address */
         privmem[1]=iop->priv_mem_size;
         privio[0]=iop->priv_io;         /* Private I/O address */
@@ -1200,7 +1245,8 @@
 
 	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
         msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
-	/* [2] and [3] filled in i2o_post_wait */
+	/* msg[2] filled in i2o_post_wait */
+	msg[3] = 0;
         msg[4] = (0<<16) | ((iop->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
         msg[5] = 0;                               /* Segment 0 */
 
@@ -1217,8 +1263,10 @@
         msg[11] = virt_to_phys(privio);
 
 	if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
-		printk(KERN_INFO "%s: Unable to set SysTab, %d\n", 
-				iop->name, ret);
+		printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", 
+			iop->name, ret);
+	else
+		dprintk((KERN_INFO "%s: SysTab set.\n", iop->name));
 
 	return ret;	
 
@@ -1229,292 +1277,114 @@
  */
 static void __init i2o_sys_init()
 {
-	struct i2o_controller *iop, *niop;
-	int ret;
-	u32 m;
+	struct i2o_controller *iop, *niop = NULL;
 
 	printk(KERN_INFO "Activating I2O controllers\n");
 	printk(KERN_INFO "This may take a few minutes if there are many devices\n");
 
-	/* Get the status for each IOP */
-	for(iop = i2o_controller_chain; iop; iop = niop)
-	{
-		niop = iop->next;
-#ifdef DRIVERDEBUG
-		printk(KERN_INFO "Getting initial status for iop%d\n", iop->unit);
-#endif
-		if(i2o_status_get(iop)<0)
-		{
-			printk("Unable to obtain status of IOP, attempting a reset.\n");
-			i2o_reset_controller(iop);
-			if(i2o_status_get(iop)<0)
-			{
-				printk("IOP not responding.\n");
-				i2o_delete_controller(iop);
-				continue;
-			}
-		}
-
-		if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED)
-		{
-			printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
-					iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-
-		if(iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
-	   	iop->status_block->iop_state == ADAPTER_STATE_READY ||
-	   	iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
-	   	iop->status_block->iop_state == ADAPTER_STATE_FAILED)
-		{
-			int msg[256];
-
-#ifdef DRIVERDEBUG
-			printk(KERN_INFO "iop%d already running...trying to reboot\n",
-					iop->unit);
-#endif
-			i2o_init_outbound_q(iop);
-			I2O_REPLY_WRITE32(iop,virt_to_phys(msg));
-			i2o_quiesce_controller(iop);
-			i2o_reset_controller(iop);
-			if(i2o_status_get(iop) || 
-				iop->status_block->iop_state != ADAPTER_STATE_RESET)
-			{
-				printk(KERN_CRIT "Failed to initialize iop%d\n", iop->unit);
-				i2o_delete_controller(iop);
-				continue;
-			}
-		}
-	}
+	/* In INIT state, Activate IOPs */
 
-	/*
-	 * Now init the outbound queue for each one.
-	 */
-	for(iop = i2o_controller_chain; iop; iop = niop)
-	{
-		int i;
-		
+	for (iop = i2o_controller_chain; iop; iop = niop) {
 		niop = iop->next;
-
-		if((ret=i2o_init_outbound_q(iop)))
-		{
-			printk(KERN_ERR 
-				"IOP%d initialization failed: Could not initialize outbound q\n",
-				iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-		iop->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
-
-		if(iop->page_frame==NULL)
-		{
-			printk(KERN_CRIT "iop%d init failed: no memory for message page.\n", 
-						iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-	
-		m=virt_to_phys(iop->page_frame);
-	
-		for(i=0; i< NMBR_MSG_FRAMES; i++)
-		{
-			I2O_REPLY_WRITE32(iop,m);
-			mb();
-			m+=MSG_FRAME_SIZE;
-			mb();
-		}
+		i2o_activate_controller(iop);
 	}
 
-	/*
-	 * OK..parse the HRT
-	 */
-	for(iop = i2o_controller_chain; iop; iop = niop)
-	{
-		niop = iop->next;
-		if(i2o_hrt_get(iop))
-		{
-			printk(KERN_CRIT "iop%d: Could not get HRT!\n", iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-		if(i2o_parse_hrt(iop))
-		{
-			printk(KERN_CRIT "iop%d: Could not parse HRT!\n", iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-	}
+	/* Active IOPs in HOLD state */
+
+rebuild_sys_tab:
+	if (i2o_controller_chain == NULL)
+		return;
 
 	/*
-	 * Build and send the system table
-	 *
 	 * If build_sys_table fails, we kill everything and bail
 	 * as we can't init the IOPs w/o a system table
 	 */	
-	if(i2o_build_sys_table())
-	{
-		printk(KERN_CRIT "I2O: Error building system table. Aborting!\n");
+	if (i2o_build_sys_table() < 0) {
 		i2o_sys_shutdown();
 		return;
 	}
 
-	for(iop = i2o_controller_chain; iop; iop = niop)
-#ifdef DRIVERDEBUG
-	{
-		niop = iop->next;
-		printk(KERN_INFO "Sending system table to iop%d\n", iop->unit);
-#endif
-		if(i2o_systab_send(iop))
-		{
-			printk(KERN_CRIT "iop%d: Error sending system table\n", iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-#ifdef DRIVERDEBUG
-	}
-#endif
-
-	/*
-	 * Enable
-	 */
-	for(iop = i2o_controller_chain; iop; iop = niop)
-	{
-		niop = iop->next;
-#ifdef DRIVERDEBUG
-		printk(KERN_INFO "Enabling iop%d\n", iop->unit);
-#endif
-		if(i2o_enable_controller(iop))
-		{
-			printk(KERN_ERR "Could not enable iop%d\n", iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-	}
-
-	/*
-	 * OK..one last thing and we're ready to go!
-	 */
-	for(iop = i2o_controller_chain; iop; iop = niop)
-	{
+	/* If IOP don't get online, we need to rebuild the System table */
+	for (iop = i2o_controller_chain; iop; iop = niop) {
 		niop = iop->next;
-#ifdef DRIVERDEBUG
-		printk(KERN_INFO "Getting LCT for iop%d\n", iop->unit);
-#endif
-		if(i2o_lct_get(iop))
-		{
-			printk(KERN_ERR "Could not get LCT from iop%d\n", iop->unit);
-			i2o_delete_controller(iop);
-			continue;
-		}
-		else	
-			i2o_parse_lct(iop);
+		if (i2o_online_controller(iop) < 0)
+			goto rebuild_sys_tab;
 	}
+	
+	/* Active IOPs now in OPERATIONAL state */
 }
 
 /*
  * Shutdown I2O system
- *
- * 1. Quiesce all controllers
- * 2. Delete all controllers
  */
 static void i2o_sys_shutdown(void)
 {
 	struct i2o_controller *iop, *niop;
 
-	for (iop = i2o_controller_chain; iop ; iop=iop->next) {
-		i2o_quiesce_controller(iop);			
-		i2o_status_get(iop);	// Update IOP status block
-	}
+	/* Delete all IOPs from the controller chain */
+	/* that will reset all IOPs too */
 
 	for (iop = i2o_controller_chain; iop; iop = niop) {
 		niop = iop->next;
-		if (i2o_delete_controller(iop))
-			iop->bus_disable(iop); 
+		i2o_delete_controller(iop);
 	}
 }
 
 /*
- *	Bring an I2O controller into HOLD state. See the 1.5
- *	spec. Basically we go
- *
- *	Wait for the message queue to initialise. 
- *	If it didnt -> controller is dead
- *	
- *	Send a get status using the message queue
- *	Poll for a reply block 88 bytes long
- *
- *	Send an initialise outbound queue
- *	Poll for a reply
- *
- *	Post our blank messages to the queue FIFO
- *
- *	Send GetHRT, Parse it
+ *	Bring an I2O controller into HOLD state. See the spec.
  */
-int i2o_activate_controller(struct i2o_controller *c)
+int i2o_activate_controller(struct i2o_controller *iop)
 {
-	return 0;
-#ifdef I2O_HOTPLUG_SUPPORT
-	u32 m;
-	int i;
-	int ret;
-
-	printk(KERN_INFO "%s: Configuring I2O controller at 0x%08X.\n",
-	       c->name, (u32)c->mem_phys);
+	/* In INIT state, Wait Inbound Q to initilaize (in i2o_status_get) */
+	/* In READY state, Get status */
 
-	if((ret=i2o_status_get(c)))
-		return ret;
+	if (i2o_status_get(iop) < 0) {
+		printk("Unable to obtain status of IOP, attempting a reset.\n");
+		i2o_reset_controller(iop);
+		if (i2o_status_get(iop) < 0) {
+			printk("IOP not responding.\n");
+			i2o_delete_controller(iop);
+			return -1;
+		}
+	}
 
-	/* not likely to be seen */
-	if(c->status_block->iop_state == ADAPTER_STATE_FAULTED) 
-	{
-		printk(KERN_CRIT "i2o: iop%d has hardware fault\n",
-		       c->unit);
+	if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) {
+		printk(KERN_CRIT "%s: hardware fault\n", iop->name);
+		i2o_delete_controller(iop);
 		return -1;
 	}
 
-	/*
-	 * If the board is running, reset it - we have no idea
-	 * what kind of a mess the previous owner left it in.
-	 * We need to feed the IOP a single outbound message
-	 * so that it can reply back to the ExecSysQuiesce.
-	 */
-	if(c->status_block->iop_state == ADAPTER_STATE_HOLD ||
-	   c->status_block->iop_state == ADAPTER_STATE_READY ||
-	   c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
-	   c->status_block->iop_state == ADAPTER_STATE_FAILED)
-	{
-		int msg[256];
-		printk(KERN_INFO "i2o/iop%d already running, reseting\n", c->unit);
-
-		if(i2o_init_outbound_q(c));
-		I2O_REPLY_WRITE32(c,virt_to_phys(msg));
-
-		if((ret=i2o_reset_controller(c)))
-			return ret;
+//	if (iop->status_block->iop_state == ADAPTER_STATE_HOLD ||
+	if (iop->status_block->iop_state == ADAPTER_STATE_READY ||
+	    iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+	    iop->status_block->iop_state == ADAPTER_STATE_FAILED)
+	{
+		dprintk((KERN_INFO "%s: already running...trying to reset\n",
+				iop->name));
+		i2o_reset_controller(iop);			
 
-		if((ret=i2o_status_get(c)))
-			return ret;
+		if (i2o_status_get(iop) < 0 || 
+			iop->status_block->iop_state != ADAPTER_STATE_RESET)
+		{
+			printk(KERN_CRIT "%s: Failed to initialize.\n", iop->name);
+			i2o_delete_controller(iop);
+			return -1;
+		}
 	}
 
-	if ((ret=i2o_init_outbound_q(c))){
-		return ret;
+	if (i2o_init_outbound_q(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
 	}
 
-	/* TODO: v2.0: Set Executive class group 000Bh - OS Operating Info */
-
-	/* 
-	 *	The outbound queue is initialised and loaded, 
-	 * 
-	 *	Now we need the Hardware Resource Table. We must ask for 
-	 *	this next we can't issue random messages yet.  
-	 */ 
-	 
-	if ((ret=i2o_hrt_get(c)))
-		return ret;
+	/* In HOLD state */
+	
+	if (i2o_hrt_get(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
+	}
 
-	return i2o_online_controller(c);
-#endif
+	return 0;
 }
 
 /*
@@ -1533,7 +1403,6 @@
 		return -ETIMEDOUT;
 	msg=(u32 *)(c->mem_offset+m);
 
-
 	status = kmalloc(4,GFP_KERNEL);
 	if (status==NULL) {
 		printk(KERN_ERR "%s: IOP reset failed - no free memory.\n",
@@ -1568,6 +1437,8 @@
 		barrier();
 	}
 
+	/* Alloc space for IOP's outbound queue message frames */
+
 	c->page_frame = kmalloc(MSG_POOL_SIZE, GFP_KERNEL);
 	if(c->page_frame==NULL) {
 		printk(KERN_CRIT "%s: Outbound Q initialize failed; out of memory.\n",
@@ -1577,6 +1448,8 @@
 	}	
 	m=virt_to_phys(c->page_frame);
 	
+	/* Post frames */
+
 	for(i=0; i< NMBR_MSG_FRAMES; i++) {
   		I2O_REPLY_WRITE32(c,m);
                 mb();
@@ -1608,15 +1481,16 @@
 
 		msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
 		msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
-		/* msg[2] and msg[3] filled in i2o_post_wait */
+		/* msg[2] filled in i2o_post_wait */
+		msg[3] = 0;
 		msg[4] = 0xFFFFFFFF;	/* All devices */
 		msg[5] = 0x00000000;	/* Report now */
 		msg[6] = 0xD0000000|size;
 		msg[7] = virt_to_bus(c->lct);
 
 		if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) {
-			printk(KERN_ERR "%s: Unable to get LCT,"
-				" Status = %d.\n", c->name,ret);	
+			printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", 
+				c->name, ret);	
 			return ret;
 		}
 
@@ -1627,83 +1501,39 @@
 		}
 	} while (c->lct == NULL);
 
+        if ((ret=i2o_parse_lct(c)) < 0)
+                return ret;
+
 	return 0;
 }
 
 
 /*
- *	Bring a controller online. Needs completing for multiple controllers
+ *	Bring a controller online into OPERATIONAL state. 
  */
  
-int i2o_online_controller(struct i2o_controller *c)
+int i2o_online_controller(struct i2o_controller *iop)
 {
-	return 0;
-#ifdef I2O_HOTPLUG_SUPPORT
-	u32 msg[10];
-	u32 privmem[2];
-	u32 privio[2];
-	int ret;
+	if (i2o_systab_send(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
+	}
 
-	/*
-	 * Build and send the system table
-	 *
-	 * If build_sys_table fails, we kill everything and bail
-	 * as we can't init the IOPs w/o a system table
-	 */
-	 
-	if (i2o_build_sys_table()) {
-	 	i2o_sys_shutdown();
-	 	return;
-	 }
-	
-	privmem[0]=c->priv_mem;		/* Private memory space base address */
-	privmem[1]=c->priv_mem_size;
-	privio[0]=c->priv_io;		/* Private I/O address */
-	privio[1]=c->priv_io_size;
-
-        __raw_writel(TEN_WORD_MSG_SIZE|SGL_OFFSET_6, &msg[0]);
-        __raw_writel(I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID, &msg$
-        __raw_writel(0, &msg[2]);               /* Context not needed */
-        __raw_writel(0, &msg[3]);
-        __raw_writel((0<<16)|(2<<12), &msg[4]); /* Host 1 I2O 2 */
-        __raw_writel(0, &msg[5]);               /* Segment 1 */
-
-        /*
-         *      Scatter Gather List
-         */
-
-        __raw_writel(0x54000000|sys_tbl_len, &msg[6]);  /* One table for now */
-        __raw_writel(virt_to_phys(sys_tbl), &msg[[7]);
-        __raw_writel(0xD4000000|48, &msg[8]);   /* One table for now */
-        __raw_writel(virt_to_phys(privmem), &msg[9]);
-
-        ret = (i2o_post_wait(c, msg, sizeof(msg), 120);
-        if (ret)
-        	return ret; 
-
-        /*
-         *      Finally we go online
-         */
-        ret = i2o_enable_controller(c);
-        if(ret)
-                return ret;
+	/* In READY state */
 
-        /*
-         *      Grab the LCT, see what is attached
-         */
-        ret=i2o_lct_get(c);
-        if(ret)
-        {
-                /* Maybe we should do also do something else */
-                return ret;
-        }
+	if (i2o_enable_controller(iop) < 0) {
+		i2o_delete_controller(iop);
+		return -1;
+	}
 
-        ret=i2o_parse_lct(c);
-        if(ret)
-                return ret;
+	/* In OPERATIONAL state  */
 
-        return 0; 
-#endif
+	if (i2o_lct_get(iop) < 0){
+		i2o_delete_controller(iop);
+		return -1;
+	}
+
+	return 0;
 }
 
 static int i2o_build_sys_table(void)
@@ -1923,7 +1753,8 @@
 
         msg[0] = I2O_MESSAGE_SIZE(5 + evt_data_len / 4) | SGL_OFFSET_5;
         msg[1] = I2O_CMD_UTIL_EVT_ACK << 24 | HOST_TID << 12 | tid;
-	/* msg[2] and msg[3] filled in i2o_post_wait */
+	msg[2] = context;
+	msg[3] = 0;
         msg[4] = evt_indicator;
         memcpy(msg+5, evt_data, evt_data_len);
 
@@ -1947,9 +1778,10 @@
 	else	
 		msg[1] = I2O_CMD_UTIL_RELEASE << 24 | HOST_TID << 12 | tid;
 
-	/* msg[2] and msg[3] filled in i2o_post_wait */	
+	/* msg[2] filled in i2o_post_wait */	
+	msg[3] = 0;
 	msg[4] = type;
-	
+
 	return i2o_post_wait(c, msg, sizeof(msg), 2);
 }
 
@@ -1970,6 +1802,8 @@
 
 	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
 	msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
+	/* msg[2] filled in i2o_post_wait */
+	msg[3] = 0;
 	msg[4] = 0;
 	msg[5] = 0x54000000 | oplen;	/* OperationBlock */
 	msg[6] = virt_to_bus(opblk);
@@ -2515,7 +2349,7 @@
 }
 
 /* Used to dump a message to syslog during debugging */
-static void i2o_dump_message(u32 *msg)
+void i2o_dump_message(u32 *msg)
 {
 #ifdef DRIVERDEBUG
 	int i;
@@ -2531,10 +2365,7 @@
 
 EXPORT_SYMBOL(i2o_install_handler);
 EXPORT_SYMBOL(i2o_remove_handler);
-EXPORT_SYMBOL(i2o_install_device);
-EXPORT_SYMBOL(i2o_delete_device);
-EXPORT_SYMBOL(i2o_quiesce_controller);
-EXPORT_SYMBOL(i2o_clear_controller);
+
 EXPORT_SYMBOL(i2o_install_controller);
 EXPORT_SYMBOL(i2o_delete_controller);
 EXPORT_SYMBOL(i2o_unlock_controller);
@@ -2547,9 +2378,7 @@
 EXPORT_SYMBOL(i2o_claim_device);
 EXPORT_SYMBOL(i2o_release_device);
 EXPORT_SYMBOL(i2o_run_queue);
-EXPORT_SYMBOL(i2o_report_controller_unit);
 EXPORT_SYMBOL(i2o_activate_controller);
-EXPORT_SYMBOL(i2o_online_controller);
 EXPORT_SYMBOL(i2o_get_class_name);
 EXPORT_SYMBOL(i2o_status_get);
 
@@ -2558,7 +2387,6 @@
 EXPORT_SYMBOL(i2o_query_table);
 EXPORT_SYMBOL(i2o_clear_table);
 EXPORT_SYMBOL(i2o_row_add_table);
-EXPORT_SYMBOL(i2o_row_delete_table);
 
 EXPORT_SYMBOL(i2o_post_this);
 EXPORT_SYMBOL(i2o_post_wait);
diff -u --recursive --new-file v2.3.38/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.3.38/linux/drivers/i2o/i2o_lan.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/i2o/i2o_lan.c	Mon Jan 10 14:05:33 2000
@@ -1,7 +1,7 @@
 /*
  *	linux/drivers/i2o/i2o_lan.c
  *
- * 	I2O LAN CLASS OSM 	December 2nd 1999
+ * 	I2O LAN CLASS OSM 	January 7th 1999
  *
  *	(C) Copyright 1999 	University of Helsinki,
  *				Department of Computer Science
@@ -18,7 +18,8 @@
  *			Deepak Saxena <deepak@plexity.net>
  *
  *	Tested:		in FDDI environment (using SysKonnect's DDM)
- *			in Ethernet environment (using Intel 82558 DDM proto)
+ *			in Gigabit Eth environment (using SysKonnect's DDM)
+ *			in Fast Ethernet environment (using Intel 82558 DDM)
  *
  *	TODO:		check error checking / timeouts
  *			code / test for other LAN classes
@@ -68,11 +69,12 @@
 	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
 	u32 bucket_count;  		/* nbr of buckets sent to DDM */
 	u32 tx_count; 	  		/* packets in one TX message frame */
-	u32 tx_max;	   		/* DDM's Tx queue len */
+	u32 tx_max_out;	   		/* DDM's Tx queue len */
 	u32 tx_out;			/* outstanding TXes */
 	u32 sgl_max;			/* max SGLs in one message frame */
 	u32 m;				/* IOP address of msg frame */
 
+	struct tq_struct i2o_batch_send_task;
 	struct sk_buff **i2o_fbl;	/* Free bucket list (to reuse skbs) */
 	int i2o_fbl_tail;
 
@@ -98,6 +100,9 @@
 	0, 0, (void (*)(void *))i2o_lan_receive_post, (void *) 0
 };
 
+/*
+ * i2o_lan_reply(): The only callback function to handle incoming messages.
+ */
 static void i2o_lan_reply(struct i2o_handler *h, struct i2o_controller *iop,
 			  struct i2o_message *m)
 {
@@ -133,7 +138,7 @@
 			}
 
 			// Something VERY wrong if this is happening
-			printk( KERN_WARNING "i2olan: Device %s rejected bucket post.\n", dev->name);
+			printk( KERN_WARNING "%s: rejected bucket post.\n", dev->name);
 		}
 
 		// Shutting down, we are getting unused buckets back
@@ -165,7 +170,7 @@
 		break;	
 	}
 
-	case LAN_RESET:
+	case LAN_RESET: 	/* default reply without payload */
 	case LAN_SUSPEND:
 		break;
 
@@ -175,12 +180,14 @@
         	break;
 
 	default:
-		printk(KERN_ERR "%s: Sorry, no handler for the reply.\n", dev->name);
+		printk(KERN_ERR "%s: No handler for the reply.\n", dev->name);
 		i2o_report_status(KERN_INFO, dev->name, msg);		
 	}
 }
 
-
+/*
+ * i2o_lan_event_reply(): Handle events.
+ */
 static void i2o_lan_event_reply(struct net_device *dev, u32 *msg)
 {
         struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -277,6 +284,9 @@
         /* Do we need to do something here too? */
 }
 
+/*
+ * i2o_lan_release_buckets(): Handle unused buckets.
+ */
 static void i2o_lan_release_buckets(struct net_device *dev, u32 *msg)
 {
         struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -292,6 +302,9 @@
 	}
 }
 
+/*
+ * i2o_lan_receive_post_reply(): Process incoming packets.
+ */
 static int i2o_lan_receive_post_reply(struct net_device *dev, u32 *msg)
 {
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
@@ -332,15 +345,17 @@
 		bucket++; // to next Packet Descriptor Block
 	}
 
-	if ((msg[4] & 0x000000FF) == I2O_LAN_DSC_BUCKET_OVERRUN)
-		printk(KERN_INFO "%s: DDM out of buckets (count = %d)!\n",
-			 dev->name, msg[5]);
+#ifdef DRIVERDEBUG
+	if (msg[5] == 0)
+		printk(KERN_INFO "%s: DDM out of buckets (priv->count = %d)!\n",
+			 dev->name, priv->bucket_count);
+#endif
 
         if (priv->bucket_count <= bucketpost - bucketthresh) {
-//        	i2o_lan_receive_post(dev);
         	i2o_post_buckets_task.data = (void *)dev;
         	queue_task(&i2o_post_buckets_task, &tq_immediate);
  		mark_bh(IMMEDIATE_BH);
+		/* Note: the task is queued only once */
 	}
                         	
 	return 0;
@@ -415,6 +430,7 @@
 	struct i2o_controller *iop = i2o_dev->controller;	
 	u32 msg[5];
 
+	dprintk(KERN_INFO "%s: LAN RESET MESSAGE.\n", dev->name);
 	msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0;
 	msg[1] = LAN_RESET<<24 | HOST_TID<<12 | i2o_dev->lct_data->tid;
 	msg[2] = priv->unit << 16 | lan_context; // InitiatorContext
@@ -453,7 +469,7 @@
 }
 
 /*
- * Set DDM into batch mode.
+ * i2o_set_batch_mode(): Set DDM into batch mode.
  */
 static void i2o_set_batch_mode(struct net_device *dev)
 {
@@ -498,9 +514,10 @@
 {
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
 	struct i2o_device *i2o_dev = priv->i2o_dev;
+#if 0
 	struct i2o_controller *iop = i2o_dev->controller;
-	u32 evt_mask =  0xFFC00007; // All generic events, all lan evenst
-
+	u32 evt_mask =  0xFFC00007; // All generic events, all lan events
+#endif
 	if (i2o_claim_device(i2o_dev, &i2o_lan_handler, I2O_CLAIM_PRIMARY)) {
 		printk(KERN_WARNING "%s: Unable to claim the I2O LAN device.\n", dev->name);
 		return -EAGAIN;
@@ -543,8 +560,8 @@
 	if (i2o_event_register(iop, i2o_dev->lct_data->tid,
 				priv->unit << 16 | lan_context, 0) < 0)
 		printk(KERN_WARNING "%s: Unable to clear the event mask.\n",
-				dev->name);
-#endif
+#endif				dev->name);
+
 	dev->tbusy = 1;
 	dev->start = 0;
 	i2o_lan_suspend(dev);
@@ -586,10 +603,6 @@
 	}
 }
 
-struct tq_struct i2o_post_send_task = {
-	0, 0, (void (*)(void *))i2o_lan_batch_send, (void *) 0
-};
-
 /*
  * i2o_lan_packet_send(): Send a packet as is, including the MAC header.
  *
@@ -598,8 +611,8 @@
  */
 static int i2o_lan_packet_send(struct sk_buff *skb, struct net_device *dev)
 {
-	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
-	struct i2o_device *i2o_dev = priv->i2o_dev;	
+	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;
+	struct i2o_device *i2o_dev = priv->i2o_dev;
 	struct i2o_controller *iop = i2o_dev->controller;
 	u32 m, *msg;
 	u32 *sgl_elem;
@@ -616,7 +629,7 @@
 	priv->tx_count++;
 	priv->tx_out++;
 
-	if (priv->tx_count == 1) {		
+	if (priv->tx_count == 1) {
 		dprintk("%s: New message frame\n", dev->name);
 
 		m = I2O_POST_READ32(iop);
@@ -635,42 +648,40 @@
 		__raw_writel((u32)skb, msg+5);  		     // TransactionContext
 		__raw_writel(virt_to_bus(skb->data), msg+6);
 
-		i2o_post_send_task.data = (void *)dev;
-        	queue_task(&i2o_post_send_task, &tq_scheduler);
-	
-		if (priv->tx_out < priv->tx_max)
-			clear_bit(0, (void *)&dev->tbusy);
+        	queue_task(&priv->i2o_batch_send_task, &tq_scheduler);
 
-		return 0;
-	}
-	
-	/* Else add new SGL element to the previous message frame */
+	} else {  /* Add new SGL element to the previous message frame */
 	
-	dprintk("%s: Adding packet %d to msg frame\n", dev->name, priv->tx_count);
+		dprintk("%s: Adding packet %d to msg frame\n", 
+			dev->name, priv->tx_count);
 
-	msg = (u32 *)(iop->mem_offset + priv->m);
-	sgl_elem = &msg[priv->tx_count * 3 + 1];
-	
-	__raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
-	__raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
-	__raw_writel(0xD5000000 | skb->len, sgl_elem);
-	__raw_writel((u32)skb, sgl_elem+1);
-	__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+		msg = (u32 *)(iop->mem_offset + priv->m);
+		sgl_elem = &msg[priv->tx_count * 3 + 1];
 
-	if (priv->tx_count == priv->sgl_max) { 	/* frame full, send now */
-//		i2o_lan_batch_send(dev);
-		i2o_post_message(iop, priv->m);
- 		dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);	
-		priv->tx_count = 0;
+		__raw_writel(I2O_MESSAGE_SIZE((__raw_readl(msg)>>16) + 3) | 1<<12 | SGL_OFFSET_4, msg);
+		__raw_writel(__raw_readl(sgl_elem-3) & 0x7FFFFFFF, sgl_elem-3); /* clear LE flag */
+		__raw_writel(0xD5000000 | skb->len, sgl_elem);
+		__raw_writel((u32)skb, sgl_elem+1);
+		__raw_writel(virt_to_bus(skb->data), sgl_elem+2);
+
+		if (priv->tx_count == priv->sgl_max) { 	/* frame full, send now */
+			i2o_post_message(iop, priv->m);
+ 			dprintk("%s: %d packets sent.\n", dev->name, priv->tx_count);	
+			priv->tx_count = 0;
+		}
 	}
+	
+	/* If HDMs TxMaxPktOut reached, stay busy (don't clean tbusy) */
 
-	if (priv->tx_out < priv->tx_max)
+	if (priv->tx_out < priv->tx_max_out)
 		clear_bit(0, (void *)&dev->tbusy);
-
+	
 	return 0;
 }
 
-
+/*
+ * i2o_lan_get_stats(): Fill in the statistics.
+ */
 static struct net_device_stats *i2o_lan_get_stats(struct net_device *dev)
 {
 	struct i2o_lan_local *priv = (struct i2o_lan_local *)dev->priv;	
@@ -882,12 +893,27 @@
         queue_task(task, &tq_scheduler);
 }
 
+/*
+ * i2o_lan_change_mtu(): Change maximum transfer unit size.
+ */
+static int i2o_lan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > 9000))
+		return -EINVAL;
+		
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+/*
+ * i2o_lan_register_device(): Register LAN class device to kernel.
+ */
 struct net_device *i2o_lan_register_device(struct i2o_device *i2o_dev)
 {
 	struct net_device *dev = NULL;
 	struct i2o_lan_local *priv = NULL;
 	u8 hw_addr[8];
-	u32 tx_max = 0;
+	u32 tx_max_out = 0;
 	unsigned short (*type_trans)(struct sk_buff *, struct net_device *);
 	void (*unregister_dev)(struct net_device *dev);
 
@@ -981,7 +1007,7 @@
 	memcpy(dev->dev_addr, hw_addr, 6);
 
 	if (i2o_query_scalar(i2o_dev->controller, i2o_dev->lct_data->tid,
-         	0x0007, 2, &tx_max, sizeof(tx_max)) < 0)
+		0x0007, 2, &tx_max_out, sizeof(tx_max_out)) < 0)
 	{
       		printk(KERN_ERR "%s: Unable to query max TX queue.\n", dev->name);
       		unit--;
@@ -989,17 +1015,23 @@
       		kfree(dev);
          	return NULL;
 	}
-   	dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max);
-   	priv->tx_max	= tx_max;
+   	dprintk(KERN_INFO "%s: Max TX Outstanding = %d.\n", dev->name, tx_max_out);
+   	priv->tx_max_out = tx_max_out;
    	priv->tx_out	= 0;
    	priv->tx_count	= 0;
 	priv->lock	= SPIN_LOCK_UNLOCKED;
 
+	priv->i2o_batch_send_task.next    = NULL;
+	priv->i2o_batch_send_task.sync    = 0;
+	priv->i2o_batch_send_task.routine = (void *)i2o_lan_batch_send;
+	priv->i2o_batch_send_task.data    = (void *)dev;
+
 	dev->open               = i2o_lan_open;
 	dev->stop               = i2o_lan_close;
 	dev->hard_start_xmit    = i2o_lan_packet_send;
 	dev->get_stats          = i2o_lan_get_stats;
 	dev->set_multicast_list = i2o_lan_set_multicast_list;
+	dev->change_mtu		= i2o_lan_change_mtu;
 
 	return dev;
 }
diff -u --recursive --new-file v2.3.38/linux/drivers/i2o/i2o_lan.h linux/drivers/i2o/i2o_lan.h
--- v2.3.38/linux/drivers/i2o/i2o_lan.h	Thu Nov 11 20:11:35 1999
+++ linux/drivers/i2o/i2o_lan.h	Mon Jan 10 14:05:33 2000
@@ -18,7 +18,7 @@
 /* Tunable parameters first */
 
 #define I2O_BUCKET_COUNT 	256
-#define I2O_BUCKET_THRESH	8
+#define I2O_BUCKET_THRESH	18 /* 9 buckets in one message */
 
 /* LAN types */
 #define I2O_LAN_ETHERNET	0x0030
diff -u --recursive --new-file v2.3.38/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.3.38/linux/drivers/i2o/i2o_proc.c	Tue Dec  7 09:32:43 1999
+++ linux/drivers/i2o/i2o_proc.c	Mon Jan 10 14:05:33 2000
@@ -29,7 +29,7 @@
 /*
  * TODO List
  *
- * - Add support for any version 2.0 spec changes once 2.0 IRTOS is
+ * - Add support for any version 2.0 spec changes once 2.0 IRTOS
  *   is available to test with
  * - Clean up code to use official structure definitions 
  */
@@ -64,8 +64,6 @@
 	write_proc_t *write_proc;	/* write func */
 } i2o_proc_entry;
 
-static int proc_context = 0;
-
 static int i2o_proc_read_lct(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_hrt(char *, char **, off_t, int, int *, void *);
 static int i2o_proc_read_status(char *, char **, off_t, int, int *, void *);
@@ -101,8 +99,6 @@
 				       struct proc_dir_entry * );
 static int create_i2o_procfs(void);
 static int destroy_i2o_procfs(void);
-static void i2o_proc_reply(struct i2o_handler *, struct i2o_controller *,
-			   struct i2o_message *);
 
 static int i2o_proc_read_lan_dev_info(char *, char **, off_t, int, int *,
 				      void *);
@@ -134,17 +130,6 @@
 static struct proc_dir_entry *i2o_proc_dir_root;
 
 /*
- * Message handler
- */
-static struct i2o_handler i2o_proc_handler =
-{
-	(void *)i2o_proc_reply,
-	"I2O procfs Layer",
-	0,
-	0xffffffff	// All classes
-};
-
-/*
  * IOP specific entries...write field just in case someone 
  * ever wants one.
  */
@@ -255,9 +240,6 @@
 	{NULL, 0, NULL, NULL}
 };
 
-
-static u32 i2o_proc_token = 0;
-
 static char *chtostr(u8 *chars, int n)
 {
 	char tmp[256];
@@ -295,12 +277,6 @@
 
 static spinlock_t i2o_proc_lock = SPIN_LOCK_UNLOCKED;
 
-void i2o_proc_reply(struct i2o_handler *phdlr, struct i2o_controller *pctrl,
-		    struct i2o_message *pmsg)
-{
-	i2o_proc_token = I2O_POST_WAIT_OK;
-}
-
 int i2o_proc_read_hrt(char *buf, char **start, off_t offset, int len, 
 		      int *eof, void *data)
 {
@@ -681,7 +657,7 @@
 				c->status_block->expected_lct_size);
 
 	len += sprintf(buf+len,"IOP Capabilities\n");
-	len += sprintf(buf+len,"   Context Field Size Support : ");
+	len += sprintf(buf+len,"    Context Field Size Support : ");
 	switch (c->status_block->iop_capabilities & 0x0000003) {
 		case 0:
 			len += sprintf(buf+len,"Supports only 32-bit context fields\n");
@@ -700,7 +676,7 @@
 		default:
 			len += sprintf(buf+len,"0x%08x\n",c->status_block->iop_capabilities);
 	}
-	len += sprintf(buf+len,"   Current Context Field Size : ");
+	len += sprintf(buf+len,"    Current Context Field Size : ");
 	switch (c->status_block->iop_capabilities & 0x0000000C) {
 		case 0:
 			len += sprintf(buf+len,"not configured\n");
@@ -718,11 +694,11 @@
 		default:
 			len += sprintf(buf+len,"\n");
 	}
-	len += sprintf(buf+len,"   Inbound Peer Support       : %s\n",
+	len += sprintf(buf+len,"    Inbound Peer Support       : %s\n",
 			(c->status_block->iop_capabilities & 0x00000010) ? "Supported" : "Not supported");
-	len += sprintf(buf+len,"   Outbound Peer Support      : %s\n",
+	len += sprintf(buf+len,"    Outbound Peer Support      : %s\n",
 			(c->status_block->iop_capabilities & 0x00000020) ? "Supported" : "Not supported");
-	len += sprintf(buf+len,"   Peer to Peer Support       : %s\n",
+	len += sprintf(buf+len,"    Peer to Peer Support       : %s\n",
 			(c->status_block->iop_capabilities & 0x00000040) ? "Supported" : "Not supported");
 
 	len += sprintf(buf+len, "Desired private memory size   : %d kB\n", 
@@ -790,17 +766,17 @@
 	len += sprintf(buf+len, "Non-Volatile Mem : %dkB\n", work32[2]>>10);
 
 	hwcap = work32[3];
-	len += sprintf(buf+len, "Capabilities :\n");
-	if(hwcap&0x00000001)
-		len += sprintf(buf+len, "   Self-booting\n");
-	if(hwcap&0x00000002)
-		len += sprintf(buf+len, "   Upgradable IRTOS\n");
-	if(hwcap&0x00000004)
-		len += sprintf(buf+len, "   Supports downloading DDMs\n");
-	if(hwcap&0x00000008)
-		len += sprintf(buf+len, "   Supports installing DDMs\n");
-	if(hwcap&0x00000010)
-		len += sprintf(buf+len, "   Battery-backed RAM\n");
+	len += sprintf(buf+len, "Capabilities : 0x%08x\n", hwcap);
+	len += sprintf(buf+len, "   [%s] Self booting\n",
+			(hwcap&0x00000001) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Upgradable IRTOS\n",
+			(hwcap&0x00000002) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Supports downloading DDMs\n",
+			(hwcap&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Supports installing DDMs\n",
+			(hwcap&0x00000008) ? "+" : "-");
+	len += sprintf(buf+len, "   [%s] Battery-backed RAM\n",
+			(hwcap&0x00000010) ? "+" : "-");
 
 	spin_unlock(&i2o_proc_lock);
 
@@ -1695,23 +1671,23 @@
 		 break;
 	}			
 
-	len += sprintf(buf+len, "Event_enable          : 0x%02X\n", result.event_enable);
-	if (result.event_enable & 0x01)
-		len += sprintf(buf+len, "\tOperational state change. \n");
-	if (result.event_enable & 0x02)
-		len += sprintf(buf+len, "\tLow catastrophic. \n");
-	if (result.event_enable & 0x04)
-		len += sprintf(buf+len, "\tLow reading. \n");
-	if (result.event_enable & 0x08)
-		len += sprintf(buf+len, "\tLow warning. \n");
-	if (result.event_enable & 0x10)
-		len += sprintf(buf+len, "\tChange back to normal from out of range state. \n");
-	if (result.event_enable & 0x20)
-		len += sprintf(buf+len, "\tHigh warning. \n");
-	if (result.event_enable & 0x40)
-		len += sprintf(buf+len, "\tHigh reading. \n");
-	if (result.event_enable & 0x80)
-		len += sprintf(buf+len, "\tHigh catastrophic. \n");
+	len += sprintf(buf+len, "Event_enable : 0x%02X\n", result.event_enable);
+	len += sprintf(buf+len, "    [%s] Operational state change. \n",
+			(result.event_enable & 0x01) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Low catastrophic. \n",
+			(result.event_enable & 0x02) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Low reading. \n",
+			(result.event_enable & 0x04) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Low warning. \n",
+			(result.event_enable & 0x08) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] Change back to normal from out of range state. \n",
+			(result.event_enable & 0x10) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] High warning. \n",
+			(result.event_enable & 0x20) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] High reading. \n",
+			(result.event_enable & 0x40) ? "+" : "-" );
+	len += sprintf(buf+len, "    [%s] High catastrophic. \n",
+			(result.event_enable & 0x80) ? "+" : "-" );
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -2187,38 +2163,37 @@
 		       work8[16],work8[17],work8[18],work8[19],
 		       work8[20],work8[21],work8[22],work8[23]);
 
-	len += sprintf(buf+len, "HW/DDM capabilities : 0x%08x\n", work32[7]);
-	len += sprintf(buf+len, "    Unicast packets %ssupported\n",
-		       (work32[7]&0x00000001)?"":"not ");
-	len += sprintf(buf+len, "    Promiscuous mode %ssupported\n",
-		       (work32[7]&0x00000002)?"":"not");
-	len += sprintf(buf+len, "    Promiscuous multicast mode %ssupported\n",
-		       (work32[7]&0x00000004)?"":"not ");
-	len += sprintf(buf+len,"    Broadcast reception disabling %ssupported\n",
-		       (work32[7]&0x00000100)?"":"not ");
-	len += sprintf(buf+len,"    Multicast reception disabling %ssupported\n",
-		       (work32[7]&0x00000200)?"":"not ");
-	len += sprintf(buf+len,"    Functional address disabling %ssupported\n",
-		       (work32[7]&0x00000400)?"":"not ");
-	len += sprintf(buf+len, "    MAC reporting %ssupported\n",
-		       (work32[7]&0x00000800)?"":"not ");
-
-	len += sprintf(buf+len, "Filter mask : 0x%08x\n", work32[6]);
-	len += sprintf(buf+len, "    Unicast packets %s\n",
-		(work32[6]&0x00000001)?"rejected":"enabled");
-	len += sprintf(buf+len, "    Promiscuous mode %s\n",
-		(work32[6]&0x00000002)?"enabled":"disabled");
-	len += sprintf(buf+len, "    Promiscuous multicast mode %s\n",
-		(work32[6]&0x00000004)?"enabled":"disabled");	
-	len += sprintf(buf+len, "    Broadcast packets %s\n",
-		(work32[6]&0x00000100)?"rejected":"enabled");
-	len += sprintf(buf+len, "    Multicast packets %s\n",
-		(work32[6]&0x00000200)?"rejected":"enabled");
-	len += sprintf(buf+len, "    Functional address %s\n",
-		       (work32[6]&0x00000400)?"ignored":"enabled");
+	len += sprintf(buf+len,"HW/DDM capabilities : 0x%08x\n", work32[7]);
+	len += sprintf(buf+len,"    [%s] Unicast packets supported\n",
+		       (work32[7]&0x00000001)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous mode supported\n",
+		       (work32[7]&0x00000002)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous multicast mode supported\n",
+		       (work32[7]&0x00000004)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Broadcast reception disabling supported\n",
+		       (work32[7]&0x00000100)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Multicast reception disabling supported\n",
+		       (work32[7]&0x00000200)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Functional address disabling supported\n",
+		       (work32[7]&0x00000400)?"+":"-");
+	len += sprintf(buf+len,"    [%s] MAC reporting supported\n",
+		       (work32[7]&0x00000800)?"+":"-");
+
+	len += sprintf(buf+len,"Filter mask : 0x%08x\n", work32[6]);
+	len += sprintf(buf+len,"    [%s] Unicast packets disable\n",
+		(work32[6]&0x00000001)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous mode enable\n",
+		(work32[6]&0x00000002)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Promiscuous multicast mode enable\n",
+		(work32[6]&0x00000004)?"+":"-");	
+	len += sprintf(buf+len,"    [%s] Broadcast packets disable\n",
+		(work32[6]&0x00000100)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Multicast packets disable\n",
+		(work32[6]&0x00000200)?"+":"-");
+	len += sprintf(buf+len,"    [%s] Functional address disable\n",
+		       (work32[6]&0x00000400)?"+":"-");
 		       
-	if (work32[7]&0x00000800)
-	{		       
+	if (work32[7]&0x00000800) {
 		len += sprintf(buf+len, "    MAC reporting mode : ");
 		if (work32[6]&0x00000800)
 			len += sprintf(buf+len, "Pass only priority MAC packets to user\n");
@@ -2321,28 +2296,10 @@
 		len += sprintf(buf+len, ", toggle");
 	len += sprintf(buf+len, "\n");
 
-	if(d->i2oversion == 0x00) { /* Reserved in 1.53 and 2.0 */
-		len += sprintf(buf+len, "Rising load delay      : %d ms\n",
-			       work32[1]/10);
-		len += sprintf(buf+len, "Rising load threshold  : %d ms\n",
-			       work32[2]/10);
-		len += sprintf(buf+len, "Falling load delay     : %d ms\n",
-			       work32[3]/10);
-		len += sprintf(buf+len, "Falling load threshold : %d ms\n",
-			       work32[4]/10);
-	}
-
-	len += sprintf(buf+len, "Max Rx batch count     : %d\n", work32[5]);
-	len += sprintf(buf+len, "Max Rx batch delay     : %d\n", work32[6]);
-
-	if(d->i2oversion == 0x00) {
-		len += sprintf(buf+len,
-			       "Transmission completion reporting delay : %d ms\n",
-			       work32[7]);
-	} else {
-		len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
-		len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
-	}
+	len += sprintf(buf+len, "Max Rx batch count : %d\n", work32[5]);
+	len += sprintf(buf+len, "Max Rx batch delay : %d\n", work32[6]);
+	len += sprintf(buf+len, "Max Tx batch delay : %d\n", work32[7]);
+	len += sprintf(buf+len, "Max Tx batch count : %d\n", work32[8]);
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -2374,37 +2331,35 @@
 				(work32[1]&0x2)?"by host":"by DDM");
 	len += sprintf(buf+len, "Packet orphan limit           : %d\n", work32[2]);
 
-	len += sprintf(buf+len, "Tx modes :\n");
-	if (work32[3]&0x00000004)
-		len += sprintf(buf+len, "    HW CRC supressed\n");
-	else
-		len += sprintf(buf+len, "    HW CRC\n");
-	if (work32[3]&0x00000100)
-		len += sprintf(buf+len, "    HW IPv4 checksumming\n");
-	if (work32[3]&0x00000200)
-		len += sprintf(buf+len, "    HW TCP checksumming\n");
-	if (work32[3]&0x00000400)
-		len += sprintf(buf+len, "    HW UDP checksumming\n");
-	if (work32[3]&0x00000800)
-		len += sprintf(buf+len, "    HW RSVP checksumming\n");
-	if (work32[3]&0x00001000)
-		len += sprintf(buf+len, "    HW ICMP checksumming\n");
-	if (work32[3]&0x00002000)
-		len += sprintf(buf+len, "    Loopback packet not delivered\n");
-
-	len += sprintf(buf+len, "Rx modes :\n");
-	if (work32[4]&0x00000004)
-		len += sprintf(buf+len, "    FCS in payload\n");
-	if (work32[4]&0x00000100)
-		len += sprintf(buf+len, "    HW IPv4 checksum validation\n");
-	if (work32[4]&0x00000200)
-		len += sprintf(buf+len, "    HW TCP checksum validation\n");
-	if (work32[4]&0x00000400)
-		len += sprintf(buf+len, "    HW UDP checksum validation\n");
-	if (work32[4]&0x00000800)
-		len += sprintf(buf+len, "    HW RSVP checksum validation\n");
-	if (work32[4]&0x00001000)
-		len += sprintf(buf+len, "    HW ICMP checksum validation\n");
+	len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]);
+	len += sprintf(buf+len, "    [%s] HW CRC supression\n",
+			(work32[3]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW IPv4 checksum\n",
+			(work32[3]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW TCP checksum\n",
+			(work32[3]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW UDP checksum\n",
+			(work32[3]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW RSVP checksum\n",
+			(work32[3]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW ICMP checksum\n",
+			(work32[3]&0x00001000) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] Loopback supression enable\n",
+			(work32[3]&0x00002000) ? "+" : "-");
+
+	len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]);
+	len += sprintf(buf+len, "    [%s] FCS in payload\n",
+			(work32[4]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW IPv4 checksum validation\n",
+			(work32[4]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW TCP checksum validation\n",
+			(work32[4]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW UDP checksum validation\n",
+			(work32[4]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW RSVP checksum validation\n",
+			(work32[4]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] HW ICMP checksum validation\n",
+			(work32[4]&0x00001000) ? "+" : "-");
  
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -2471,16 +2426,8 @@
 		len += sprintf(buf+len, "Unspecified\n");
 	}
 	
-	if (d->i2oversion == 0x00) /* Reserved in 1.53 and 2.0 */
-	{
-		len += sprintf(buf+len, "Bad packets handled by : %s\n",
-			       (result.reserved == 0xFF)?"host":"DDM");
-	}
-	else
-	{
-		len += sprintf(buf+len, "Duplex mode target     : ");
-		switch (result.duplex_mode_target)
-		{
+	len += sprintf(buf+len, "Duplex mode target     : ");
+	switch (result.duplex_mode_target){
 		case 0:
 			len += sprintf(buf+len, "Half duplex\n");
 			break;
@@ -2489,14 +2436,13 @@
 			break;
 		default:
 			len += sprintf(buf+len, "\n");
-		}
-
-		len += sprintf(buf+len, "Connector type target  : %s\n",
-			       i2o_get_connector_type(result.connector_type_target));
-		len += sprintf(buf+len, "Connection type target : %s\n",
-			       i2o_get_connection_type(result.connection_type_target));
 	}
 
+	len += sprintf(buf+len, "Connector type target  : %s\n",
+		       i2o_get_connector_type(result.connector_type_target));
+	len += sprintf(buf+len, "Connection type target : %s\n",
+		       i2o_get_connection_type(result.connection_type_target));
+
 	spin_unlock(&i2o_proc_lock);
 	return len;
 }
@@ -2568,46 +2514,34 @@
 		return len;
 	}
 
-	len += sprintf(buf,     "Max SG Elements per packet : %d\n", work32[0]);
-	len += sprintf(buf+len, "Max SG Elements per chain  : %d\n", work32[1]);
-	len += sprintf(buf+len, "Max outstanding packets    : %d\n", work32[2]);
-	len += sprintf(buf+len, "Max packets per request    : %d\n", work32[3]);
-
-	len += sprintf(buf+len, "Tx modes :\n");
-	if(work32[4]&0x00000002)
-		len += sprintf(buf+len, "    No DA in SGL\n");
-	if(work32[4]&0x00000004)
-		len += sprintf(buf+len, "    CRC suppression\n");
-	if(work32[4]&0x00000008)
-		len += sprintf(buf+len, "    Loop suppression\n");
-	if(work32[4]&0x00000010)
-		len += sprintf(buf+len, "    MAC insertion\n");
-	if(work32[4]&0x00000020)
-		len += sprintf(buf+len, "    RIF insertion\n");
-	if(work32[4]&0x00000100)
-		len += sprintf(buf+len, "    IPv4 checksum\n");
-	if(work32[4]&0x00000200)
-		len += sprintf(buf+len, "    TCP checksum\n");
-	if(work32[4]&0x00000400)
-		len += sprintf(buf+len, "    UDP checksum\n");
-	if(work32[4]&0x00000800)
-		len += sprintf(buf+len, "    RSVP checksum\n");
-	if(work32[4]&0x00001000)
-		len += sprintf(buf+len, "    ICMP checksum\n");
-	if (d->i2oversion == 0x00)
-	{
-		if(work32[4]&0x00008000)
-			len += sprintf(buf+len, "    Loopback enabled\n");
-		if(work32[4]&0x00010000)
-			len += sprintf(buf+len, "    Loopback suppression enabled\n");
-	}
-	else
-	{
-		if(work32[4]&0x00010000)
-			len += sprintf(buf+len, "    Loopback enabled\n");
-		if(work32[4]&0x00020000)
-			len += sprintf(buf+len, "    Loopback suppression enabled\n");
-	}
+	len += sprintf(buf,     "Tx Max SG elements per packet : %d\n", work32[0]);
+	len += sprintf(buf+len, "Tx Max SG elements per chain  : %d\n", work32[1]);
+	len += sprintf(buf+len, "Tx Max outstanding packets    : %d\n", work32[2]);
+	len += sprintf(buf+len, "Tx Max packets per request    : %d\n", work32[3]);
+
+	len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[4]);
+	len += sprintf(buf+len, "    [%s] No DA in SGL\n",
+				(work32[4]&0x00000002) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] CRC suppression\n",
+				(work32[4]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] MAC insertion\n",
+				(work32[4]&0x00000010) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] RIF insertion\n",
+				(work32[4]&0x00000020) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] IPv4 checksum generation\n",
+				(work32[4]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] TCP checksum generation\n",
+				(work32[4]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] UDP checksum generation\n",
+				(work32[4]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] RSVP checksum generation\n",
+				(work32[4]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] ICMP checksum generation\n",
+				(work32[4]&0x00001000) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] Loopback enabled\n",
+				(work32[4]&0x00010000) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] Loopback suppression enabled\n",
+				(work32[4]&0x00020000) ? "+" : "-");
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -2632,15 +2566,25 @@
 		return len;
 	}
 
-	len += sprintf(buf,"Max size of chain element : %d\n", work32[0]);
-	len += sprintf(buf+len, "Max number of buckets     : %d\n", work32[1]);
-
-	if (d->i2oversion > 0x00) { /* not in 1.5 */
-		len += sprintf(buf+len, "RxModes                   : %d\n", work32[2]);
-		len += sprintf(buf+len, "RxMaxBucketsReply         : %d\n", work32[3]);
-		len += sprintf(buf+len, "RxMaxPacketsPerBuckets    : %d\n", work32[4]);
-		len += sprintf(buf+len, "RxMaxPostBuckets          : %d\n", work32[5]);
-	}
+	len += sprintf(buf     ,"Rx Max size of chain element : %d\n", work32[0]);
+	len += sprintf(buf+len, "Rx Max Buckets               : %d\n", work32[1]);
+	len += sprintf(buf+len, "Rx Max Buckets in Reply      : %d\n", work32[3]);
+	len += sprintf(buf+len, "Rx Max Packets in Bucket     : %d\n", work32[4]);
+	len += sprintf(buf+len, "Rx Max Buckets in Post       : %d\n", work32[5]);
+
+	len += sprintf(buf+len, "Rx Modes : 0x%08x\n", work32[2]);
+	len += sprintf(buf+len, "    [%s] FCS reception\n",
+				(work32[2]&0x00000004) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] IPv4 checksum validation \n",
+				(work32[2]&0x00000100) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] TCP checksum validation \n",
+				(work32[2]&0x00000200) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] UDP checksum validation \n",
+				(work32[2]&0x00000400) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] RSVP checksum validation \n",
+				(work32[2]&0x00000800) ? "+" : "-");
+	len += sprintf(buf+len, "    [%s] ICMP checksum validation \n",
+				(work32[2]&0x00001000) ? "+" : "-");
 
 	spin_unlock(&i2o_proc_lock);
 	return len;
@@ -3344,14 +3288,6 @@
 	if(create_i2o_procfs())
 		return -EBUSY;
 
-	if (i2o_install_handler(&i2o_proc_handler) < 0)
-	{
-		printk(KERN_ERR "i2o_proc: Unable to install PROC handler.\n");
-		return 0;
-	}
-
-	proc_context = i2o_proc_handler.context;
-
 	return 0;
 }
 
@@ -3364,6 +3300,5 @@
 void cleanup_module(void)
 {
 	destroy_i2o_procfs();
-	i2o_remove_handler(&i2o_proc_handler);
 }
 #endif
diff -u --recursive --new-file v2.3.38/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.3.38/linux/drivers/net/3c509.c	Fri Oct 15 15:25:13 1999
+++ linux/drivers/net/3c509.c	Mon Jan 10 14:05:32 2000
@@ -374,6 +374,7 @@
 	
 	((struct el3_private *)dev->priv)->mca_slot = mca_slot;
 	((struct el3_private *)dev->priv)->next_dev = el3_root_dev;
+	((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 	el3_root_dev = dev;
 
 	if (el3_debug > 0)
@@ -433,9 +434,6 @@
 	outw(TxReset, ioaddr + EL3_CMD);
 	outw(RxReset, ioaddr + EL3_CMD);
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
-
-	/* Set the spinlock before grabbing IRQ! */
-	((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 
 	if (request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev)) {
 		return -EAGAIN;
diff -u --recursive --new-file v2.3.38/linux/drivers/net/oaknet.c linux/drivers/net/oaknet.c
--- v2.3.38/linux/drivers/net/oaknet.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/oaknet.c	Mon Jan 10 18:25:32 2000
@@ -0,0 +1,546 @@
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: oaknet.c
+ *
+ *    Description:
+ *      Driver for the National Semiconductor DP83902AV Ethernet controller
+ *      on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
+ *      various other 8390 drivers written by Donald Becker and Paul Gortmaker.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/board.h>
+#include <asm/io.h>
+
+#include "8390.h"
+
+
+/* Preprocessor Defines */
+
+#if !defined(TRUE) || TRUE != 1
+#define	TRUE	1
+#endif
+
+#if !defined(FALSE) || FALSE != 0
+#define	FALSE	0
+#endif
+
+#define	OAKNET_CMD     		0x00
+#define OAKNET_DATA		0x10	/* NS-defined port window offset. */
+#define OAKNET_RESET		0x1f	/* A read resets, a write clears. */
+
+#define	OAKNET_START_PG		0x20	/* First page of TX buffer */
+#define	OAKNET_STOP_PG		0x40	/* Last pagge +1 of RX ring */
+
+#define	OAKNET_BASE		(dev->base_addr)
+
+#define	OAKNET_WAIT		(2 * HZ / 100)	/* 20 ms */
+
+
+/* Global Variables */
+
+#if defined(MODULE)
+static struct net_device *oaknet_devs;
+#endif
+
+
+/* Function Prototypes */
+
+static int	 oaknet_open(struct net_device *dev);
+static int	 oaknet_close(struct net_device *dev);
+
+static void	 oaknet_reset_8390(struct net_device *dev);
+static void	 oaknet_get_8390_hdr(struct net_device *dev,
+				     struct e8390_pkt_hdr *hdr, int ring_page);
+static void	 oaknet_block_input(struct net_device *dev, int count,
+				    struct sk_buff *skb, int ring_offset);
+static void	 oaknet_block_output(struct net_device *dev, int count,
+				     const unsigned char *buf, int start_page);
+
+static void	 oaknet_dma_error(struct net_device *dev, const char *name);
+
+
+/*
+ * int oaknet_init()
+ *
+ * Description:
+ *   This routine performs all the necessary platform-specific initiali-
+ *   zation and set-up for the IBM "Oak" evaluation board's National
+ *   Semiconductor DP83902AV "ST-NIC" Ethernet controller.
+ *
+ * Input(s):
+ *   N/A
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   0 if OK, otherwise system error number on error.
+ *
+ */
+int
+oaknet_init(void)
+{
+	register int i;
+	int reg0, regd;
+	struct net_device *dev = NULL;
+	unsigned long ioaddr = OAKNET_IO_BASE;
+	const char *name = "National DP83902AV";
+	bd_t *bip = (bd_t *)__res;
+
+	/* Quick register check to see if the device is really there. */
+
+	if ((reg0 = inb_p(ioaddr)) == 0xFF)
+		return (ENODEV);
+
+	/*
+	 * That worked. Now a more thorough check, using the multicast
+	 * address registers, that the device is definitely out there
+	 * and semi-functional.
+	 */
+
+	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);
+	regd = inb_p(ioaddr + 0x0D);
+	outb_p(0xFF, ioaddr + 0x0D);
+	outb_p(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
+	inb_p(ioaddr + EN0_COUNTER0);
+
+	/* It's no good. Fix things back up and leave. */
+
+	if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
+		outb_p(reg0, ioaddr);
+		outb_p(regd, ioaddr + 0x0D);
+		dev->base_addr = 0;
+
+		return (ENODEV);
+	}
+
+	/*
+	 * We're dependent on the 8390 generic driver module, make
+	 * sure its symbols are loaded.
+	 */
+
+	if (load_8390_module("oaknet.c"))
+		return (-ENOSYS);
+
+	/*
+	 * We're not using the old-style probing API, so we have to allocate
+	 * our own device structure.
+	 */
+
+	dev = init_etherdev(0, 0);
+#if defined(MODULE)
+	oaknet_devs = dev;
+#endif
+
+	/*
+	 * This controller is on an embedded board, so the base address
+	 * and interrupt assignments are pre-assigned and unchageable.
+	 */
+
+	dev->base_addr = OAKNET_IO_BASE;
+	dev->irq = OAKNET_INT;
+
+	/* Allocate 8390-specific device-private area and fields. */
+
+	if (ethdev_init(dev)) {
+		printk(" unable to get memory for dev->priv.\n");
+		return (-ENOMEM);
+	}
+
+	/*
+	 * Just to be safe, reset the card as we cannot really* be sure
+	 * what state it was last left in.
+	 */
+
+	oaknet_reset_8390(dev);
+
+	/*
+	 * Disable all chip interrupts for now and ACK all pending
+	 * interrupts.
+	 */
+
+	outb_p(0x0, ioaddr + EN0_IMR);
+	outb_p(0xFF, ioaddr + EN0_ISR);
+
+	/* Attempt to get the interrupt line */
+
+	if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
+		printk("%s: unable to request interrupt %d.\n",
+		       dev->name, dev->irq);
+		kfree(dev->priv);
+		dev->priv = NULL;
+		return (EAGAIN);
+	}
+
+	request_region(dev->base_addr, OAKNET_IO_SIZE, name);
+
+	/* Tell the world about what and where we've found. */
+
+	printk("%s: %s at", dev->name, name);
+	for (i = 0; i < ETHER_ADDR_LEN; ++i) {
+		dev->dev_addr[i] = bip->bi_enetaddr[i];
+		printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);
+	}
+	printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);
+
+	/* Set up some required driver fields and then we're done. */
+
+	ei_status.name		= name;
+	ei_status.word16	= FALSE;
+	ei_status.tx_start_page	= OAKNET_START_PG;
+	ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;
+	ei_status.stop_page	= OAKNET_STOP_PG;
+
+	ei_status.reset_8390	= &oaknet_reset_8390;
+	ei_status.block_input	= &oaknet_block_input;
+	ei_status.block_output	= &oaknet_block_output;
+	ei_status.get_8390_hdr	= &oaknet_get_8390_hdr;
+
+	dev->open = oaknet_open;
+	dev->stop = oaknet_close;
+
+	NS8390_init(dev, FALSE);
+
+	return (0);
+}
+
+/*
+ * static int oaknet_open()
+ *
+ * Description:
+ *   This routine is a modest wrapper around ei_open, the 8390-generic,
+ *   driver open routine. This just increments the module usage count
+ *   and passes along the status from ei_open.
+ *
+ * Input(s):
+ *  *dev - Pointer to the device structure for this driver.
+ *
+ * Output(s):
+ *  *dev - Pointer to the device structure for this driver, potentially
+ *         modified by ei_open.
+ *
+ * Returns:
+ *   0 if OK, otherwise < 0 on error.
+ *
+ */
+static int
+oaknet_open(struct net_device *dev)
+{
+	int status = ei_open(dev);
+	MOD_INC_USE_COUNT;
+	return (status);
+}
+
+/*
+ * static int oaknet_close()
+ *
+ * Description:
+ *   This routine is a modest wrapper around ei_close, the 8390-generic,
+ *   driver close routine. This just decrements the module usage count
+ *   and passes along the status from ei_close.
+ *
+ * Input(s):
+ *  *dev - Pointer to the device structure for this driver.
+ *
+ * Output(s):
+ *  *dev - Pointer to the device structure for this driver, potentially
+ *         modified by ei_close.
+ *
+ * Returns:
+ *   0 if OK, otherwise < 0 on error.
+ *
+ */
+static int
+oaknet_close(struct net_device *dev)
+{
+	int status = ei_close(dev);
+	MOD_DEC_USE_COUNT;
+	return (status);
+}
+
+/*
+ * static void oaknet_reset_8390()
+ *
+ * Description:
+ *   This routine resets the DP83902 chip.
+ *
+ * Input(s):
+ *  *dev - 
+ *
+ * Output(s):
+ *   N/A
+ *
+ * Returns:
+ *   N/A
+ *
+ */
+static void
+oaknet_reset_8390(struct net_device *dev)
+{
+	int base = OAKNET_BASE;
+	unsigned long start = jiffies;
+
+	outb(inb(base + OAKNET_RESET), base + OAKNET_RESET);
+
+	ei_status.txing = 0;
+	ei_status.dmaing = 0;
+
+	/* This check shouldn't be necessary eventually */
+
+	while ((inb_p(base + EN0_ISR) & ENISR_RESET) == 0) {
+		if (jiffies - start > OAKNET_WAIT) {
+			printk("%s: reset didn't complete\n", dev->name);
+			break;
+		}
+	}
+
+	outb_p(ENISR_RESET, base + EN0_ISR);	/* ACK reset interrupt */
+
+	return;
+}
+
+/*
+ * XXX - Document me.
+ */
+static void
+oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+		    int ring_page)
+{
+	int base = OAKNET_BASE;
+
+	/*
+	 * This should NOT happen. If it does, it is the LAST thing you'll
+	 * see.
+	 */
+
+	if (ei_status.dmaing) {
+		oaknet_dma_error(dev, "oaknet_get_8390_hdr");
+		return;
+	}
+
+	ei_status.dmaing |= 0x01;
+	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
+	outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO);
+	outb_p(0, base + EN0_RCNTHI);
+	outb_p(0, base + EN0_RSARLO);		/* On page boundary */
+	outb_p(ring_page, base + EN0_RSARHI);
+	outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
+
+	if (ei_status.word16)
+		insw(base + OAKNET_DATA, hdr,
+		     sizeof(struct e8390_pkt_hdr) >> 1);
+	else
+		insb(base + OAKNET_DATA, hdr,
+		     sizeof(struct e8390_pkt_hdr));
+
+	outb_p(ENISR_RDC, base + EN0_ISR);	/* ACK Remote DMA interrupt */
+	ei_status.dmaing &= ~0x01;
+
+	return;
+}
+
+/*
+ * XXX - Document me.
+ */
+static void
+oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
+		   int ring_offset)
+{
+	int base = OAKNET_BASE;
+	char *buf = skb->data;
+
+	/*
+	 * This should NOT happen. If it does, it is the LAST thing you'll
+	 * see.
+	 */
+
+	if (ei_status.dmaing) {
+		oaknet_dma_error(dev, "oaknet_block_input");
+		return;
+	}
+
+	ei_status.dmaing |= 0x01;
+	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
+	outb_p(count & 0xff, base + EN0_RCNTLO);
+	outb_p(count >> 8, base + EN0_RCNTHI);
+	outb_p(ring_offset & 0xff, base + EN0_RSARLO);
+	outb_p(ring_offset >> 8, base + EN0_RSARHI);
+	outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
+	if (ei_status.word16) {
+		insw(base + OAKNET_DATA, buf, count >> 1);
+		if (count & 0x01) {
+			buf[count-1] = inb(base + OAKNET_DATA);
+		}
+	} else {
+		insb(base + OAKNET_DATA, buf, count);
+	}
+	outb_p(ENISR_RDC, base + EN0_ISR);	/* ACK Remote DMA interrupt */
+	ei_status.dmaing &= ~0x01;
+
+	return;
+}
+
+/*
+ * XXX - Document me.
+ */
+static void
+oaknet_block_output(struct net_device *dev, int count,
+		    const unsigned char *buf, int start_page)
+{
+	int base = OAKNET_BASE;
+	int bug;
+	unsigned long start;
+	unsigned char lobyte;
+
+	/* Round the count up for word writes. */
+
+	if (ei_status.word16 && (count & 0x1))
+		count++;
+
+	/*
+	 * This should NOT happen. If it does, it is the LAST thing you'll
+	 * see.
+	 */
+
+	if (ei_status.dmaing) {
+		oaknet_dma_error(dev, "oaknet_block_output");
+		return;
+	}
+
+	ei_status.dmaing |= 0x01;
+
+	/* Make sure we are in page 0. */
+
+	outb_p(E8390_PAGE0 + E8390_START + E8390_NODMA, base + OAKNET_CMD);
+
+	/*
+	 * The 83902 documentation states that the processor needs to
+	 * do a "dummy read" before doing the remote write to work
+	 * around a chip bug they don't feel like fixing.
+	 */
+
+	bug = 0;
+	while (1) {
+		unsigned int rdhi;
+		unsigned int rdlo;
+
+		/* Now the normal output. */
+		outb_p(ENISR_RDC, base + EN0_ISR);
+		outb_p(count & 0xff, base + EN0_RCNTLO);
+		outb_p(count >> 8,   base + EN0_RCNTHI);
+		outb_p(0x00, base + EN0_RSARLO);
+		outb_p(start_page, base + EN0_RSARHI);
+
+		if (bug++)
+			break;
+
+		/* Perform the dummy read */
+		rdhi = inb_p(base + EN0_CRDAHI);
+		rdlo = inb_p(base + EN0_CRDALO);
+		outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
+
+		while (1) {
+			unsigned int nrdhi;
+			unsigned int nrdlo;
+			nrdhi = inb_p(base + EN0_CRDAHI);
+			nrdlo = inb_p(base + EN0_CRDALO);
+			if ((rdhi != nrdhi) || (rdlo != nrdlo))
+				break;
+		}
+	}
+
+	outb_p(E8390_RWRITE+E8390_START, base + OAKNET_CMD);
+	if (ei_status.word16) {
+		outsw(OAKNET_BASE + OAKNET_DATA, buf, count >> 1);
+	} else {
+		outsb(OAKNET_BASE + OAKNET_DATA, buf, count);
+	}
+
+	start = jiffies;
+
+	while (((lobyte = inb_p(base + EN0_ISR)) & ENISR_RDC) == 0) {
+		if (jiffies - start > OAKNET_WAIT) {
+			unsigned char hicnt, locnt;
+			hicnt = inb_p(base + EN0_CRDAHI);
+			locnt = inb_p(base + EN0_CRDALO);
+			printk("%s: timeout waiting for Tx RDC, stat = 0x%x\n",
+			       dev->name, lobyte);
+			printk("\tstart address 0x%x, current address 0x%x, count %d\n",
+			       (start_page << 8), (hicnt << 8) | locnt, count);
+			oaknet_reset_8390(dev);
+			NS8390_init(dev, TRUE);
+			break;
+		}
+	}
+	
+	outb_p(ENISR_RDC, base + EN0_ISR);	/* Ack intr. */
+	ei_status.dmaing &= ~0x01;
+
+	return;
+}
+
+static void
+oaknet_dma_error(struct net_device *dev, const char *name)
+{
+	printk(KERN_EMERG "%s: DMAing conflict in %s."
+	       "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
+	       dev->name, name, ei_status.dmaing, ei_status.irqlock,
+	       dev->interrupt);
+
+	return;
+}
+
+#if defined(MODULE)
+/*
+ * Oak Ethernet module load interface.
+ */
+int
+init_module(void)
+{
+	int status;
+
+	if (oaknet_devs != NULL)
+		return (-EBUSY);
+
+	status = oaknet_init()
+
+	lock_8390_module();
+
+	return (status);
+}
+
+/*
+ * Oak Ethernet module unload interface.
+ */
+void
+cleanup_module(void)
+{
+	if (oaknet_devs == NULL)
+		return;
+
+	if (oaknet_devs->priv != NULL) {
+		int ioaddr = oaknet_devs->base_addr;
+		void *priv = oaknet_devs->priv;
+		free_irq(oaknet_devs->irq, oaknet_devs);
+		release_region(ioaddr, OAKNET_IO_SIZE);
+		unregister_netdev(oaknet_dev);
+		kfree(priv);
+	}
+
+	oaknet_devs = NULL;
+
+	unlock_8390_module();
+
+	return;
+}
+#endif /* MODULE */
diff -u --recursive --new-file v2.3.38/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c
--- v2.3.38/linux/drivers/net/pcmcia/tulip_cb.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/net/pcmcia/tulip_cb.c	Sat Jan  8 12:43:56 2000
@@ -39,13 +39,6 @@
 	"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
 };
 
-/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
-#ifdef REVERSE_PROBE_ORDER
-static int reverse_probe = 1;
-#else
-static int reverse_probe = 0;
-#endif
-
 /* Keep the ring sizes a power of two for efficiency.
    Making the Tx ring too large decreases the effectiveness of channel
    bonding and packet priority.
@@ -126,6 +119,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -284,7 +278,6 @@
 	struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
 							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
 };
-#ifndef CARDBUS
 static struct pci_id_info pci_tbl[] = {
   { "Digital DC21040 Tulip",
 	0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
@@ -310,9 +303,10 @@
 	0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
   { "Compex RL100-TX",
 	0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Xircom Cardbus Adapter (DEC 21143 compatible mode)",
+	0x115D, 0x0003, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
   {0},
 };
-#endif /* !CARD_BUS */
 
 /* This table use during operation for capabilities and media timer. */
 
@@ -456,7 +450,6 @@
 struct tulip_private {
 	char devname[8];			/* Used only for kernel debugging. */
 	const char *product_name;
-	struct net_device *next_module;
 	struct tulip_rx_desc rx_ring[RX_RING_SIZE];
 	struct tulip_tx_desc tx_ring[TX_RING_SIZE];
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -574,107 +567,6 @@
     restore_flags(flags);
 }
 
-/* A list of all installed Tulip devices. */
-static struct net_device *root_tulip_dev = NULL;
-
-#ifndef CARDBUS
-int tulip_probe(struct net_device *dev)
-{
-	int cards_found = 0;
-	int pci_index = 0;
-	unsigned char pci_bus, pci_device_fn;
-
-	if ( ! pcibios_present())
-		return -ENODEV;
-
-	for (;pci_index < 0xff; pci_index++) {
-		u16 vendor, device, pci_command, new_command;
-		int chip_idx;
-		int irq;
-		long ioaddr;
-
-		if (pcibios_find_class
-			(PCI_CLASS_NETWORK_ETHERNET << 8,
-			 reverse_probe ? 0xfe - pci_index : pci_index,
-			 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
-			if (reverse_probe)
-				continue;
-			else
-				break;
-		}
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_VENDOR_ID, &vendor);
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_DEVICE_ID, &device);
-
-		for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-			if (vendor == pci_tbl[chip_idx].vendor_id
-				&& (device & pci_tbl[chip_idx].device_id_mask) ==
-				pci_tbl[chip_idx].device_id)
-				break;
-		if (pci_tbl[chip_idx].vendor_id == 0)
-			continue;
-
-		{
-#if defined(PCI_SUPPORT_VER2)
-			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-			ioaddr = pdev->base_address[0] & ~3;
-			irq = pdev->irq;
-#elif defined(PCI_SUPPORT_VER3)
-			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-			ioaddr = pdev->resource[0].start;
-			irq = pdev->irq;
-#else
-			u32 pci_ioaddr;
-			u8 pci_irq_line;
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_INTERRUPT_LINE, &pci_irq_line);
-			ioaddr = pci_ioaddr & ~3;
-			irq = pci_irq_line;
-#endif
-		}
-
-		if (debug > 2)
-			printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n",
-				   pci_tbl[chip_idx].name, ioaddr);
-
-		pcibios_read_config_word(pci_bus, pci_device_fn,
-								 PCI_COMMAND, &pci_command);
-		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
-		if (pci_command != new_command) {
-			printk(KERN_INFO "  The PCI BIOS has not enabled the"
-				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
-				   pci_bus, pci_device_fn, pci_command, new_command);
-			pcibios_write_config_word(pci_bus, pci_device_fn,
-									  PCI_COMMAND, new_command);
-		}
-
-		dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
-									   irq, chip_idx, cards_found);
-
-		/* Get and check the bus-master and latency values. */
-		if (dev) {
-			u8 pci_latency;
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_LATENCY_TIMER, &pci_latency);
-			if (pci_latency < 10) {
-				printk(KERN_INFO "  PCI latency timer (CFLT) is "
-					   "unreasonably low at %d.  Setting to 64 clocks.\n",
-					   pci_latency);
-				pcibios_write_config_byte(pci_bus, pci_device_fn,
-										  PCI_LATENCY_TIMER, 64);
-			}
-		}
-		dev = 0;
-		cards_found++;
-	}
-
-	return cards_found ? 0 : -ENODEV;
-}
-#endif  /* not CARDBUS */
-
 static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
 								   struct net_device *dev, long ioaddr, int irq,
 								   int chip_idx, int board_idx)
@@ -851,9 +743,6 @@
 	memset(tp, 0, sizeof(*tp));
 	dev->priv = tp;
 
-	tp->next_module = root_tulip_dev;
-	root_tulip_dev = dev;
-
 	tp->pci_bus = pci_bus;
 	tp->pci_devfn = pci_devfn;
 	tp->chip_id = chip_idx;
@@ -3251,127 +3140,82 @@
 	outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id);
 }
 
-#ifdef CARDBUS
-
-#include <pcmcia/driver_ops.h>
-
-static dev_node_t *tulip_attach(dev_locator_t *loc)
+static int tulip_probe(struct pci_dev *pdev)
 {
 	struct net_device *dev;
-	u16 dev_id;
-	u16 vendor_id;
-	u32 io;
-	u8 bus, devfn, irq;
-
-	if (loc->bus != LOC_PCI) return NULL;
-	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-	printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
-	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
-	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-	pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
-	if (dev_id == 0x0003 && vendor_id == 0x115d) 
-		dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, X3201_3, 0);
-	else
-		dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, DC21142, 0);
+	int chip_idx;
+	static int board_idx = 0;
+
+	printk(KERN_INFO "tulip_attach(%s)\n", pdev->slot_name);
+
+	for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+		if (pdev->vendor == pci_tbl[chip_idx].vendor_id
+		    && (pdev->device & pci_tbl[chip_idx].device_id_mask) ==
+		    pci_tbl[chip_idx].device_id)
+			break;
+	if (pci_tbl[chip_idx].vendor_id == 0)
+		return 0;
+
+	pci_set_master(pdev);
+	dev = pci_tbl[chip_idx].probe1(pdev->bus->number, pdev->devfn, NULL,
+				       pdev->resource[0].start, pdev->irq,
+				       chip_idx, board_idx++);
 	if (dev) {
-		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-		strcpy(node->dev_name, dev->name);
-		node->major = node->minor = 0;
-		node->next = NULL;
+		pdev->driver_data = dev;
 		MOD_INC_USE_COUNT;
-		return node;
+		return 1;
 	}
-	return NULL;
+	return 0;
 }
 
-static void tulip_suspend(dev_node_t *node)
+static void tulip_suspend(struct pci_dev *pdev)
 {
-	struct net_device *dev, *next;
-	printk(KERN_INFO "tulip_suspend(%s)\n", node->dev_name);
-	for (dev = root_tulip_dev; dev; dev = next) {
-		next = ((struct tulip_private *)dev->priv)->next_module;
-		if (strcmp(dev->name, node->dev_name) == 0) break;
-	}
-	if (dev) {
-		struct tulip_private *tp = (struct tulip_private *)dev->priv;
-		if (tp->open) tulip_down(dev);
-	}
+	struct net_device *dev = pdev->driver_data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	printk(KERN_INFO "tulip_suspend(%s)\n", dev->name);
+	if (tp->open) tulip_down(dev);
 }
 
-static void tulip_resume(dev_node_t *node)
+static void tulip_resume(struct pci_dev *pdev)
 {
-	struct net_device *dev, *next;
-	printk(KERN_INFO "tulip_resume(%s)\n", node->dev_name);
-	for (dev = root_tulip_dev; dev; dev = next) {
-		next = ((struct tulip_private *)dev->priv)->next_module;
-		if (strcmp(dev->name, node->dev_name) == 0) break;
-	}
-	if (dev) {
-		struct tulip_private *tp = (struct tulip_private *)dev->priv;
-		if (tp->open) tulip_up(dev);
-	}
+	struct net_device *dev = pdev->driver_data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	printk(KERN_INFO "tulip_resume(%s)\n", dev->name);
+	if (tp->open) tulip_up(dev);
 }
 
-static void tulip_detach(dev_node_t *node)
+static void tulip_remove(struct pci_dev *pdev)
 {
-	struct net_device **devp, **next;
-	printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
-	for (devp = &root_tulip_dev; *devp; devp = next) {
-		next = &((struct tulip_private *)(*devp)->priv)->next_module;
-		if (strcmp((*devp)->name, node->dev_name) == 0) break;
-	}
-	if (*devp) {
-		struct net_device *dev = *devp;
-		struct tulip_private *tp = dev->priv;
-		*devp = *next;
-		unregister_netdev(dev);
-		kfree(dev);
-		kfree(tp);
-		kfree(node);
-		MOD_DEC_USE_COUNT;
-	}
+	struct net_device *dev = pdev->driver_data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+	printk(KERN_INFO "tulip_detach(%s)\n", dev->name);
+	unregister_netdev(dev);
+	kfree(dev);
+	kfree(tp);
 }
 
-struct driver_operations tulip_ops = {
-	"tulip_cb", tulip_attach, tulip_suspend, tulip_resume, tulip_detach
+struct pci_driver tulip_ops = {
+	name:		"tulip_cb",
+	probe:		tulip_probe,
+	remove:		tulip_remove,
+	suspend:	tulip_suspend,
+	resume:		tulip_resume
 };
 
-#endif  /* Cardbus support */
-
-#ifdef MODULE
-int init_module(void)
+int __init tulip_init(void)
 {
-#ifdef CARDBUS
-	reverse_probe = 0;			/* Not used. */
-	register_driver(&tulip_ops);
+	pci_register_driver(&tulip_ops);
 	return 0;
-#else
-	return tulip_probe(NULL);
-#endif
 }
 
-void cleanup_module(void)
+void __exit tulip_cleanup(void)
 {
-	struct net_device *next_dev;
-
-#ifdef CARDBUS
-	unregister_driver(&tulip_ops);
-#endif
-
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (root_tulip_dev) {
-		struct tulip_private *tp = (struct tulip_private *)root_tulip_dev->priv;
-		next_dev = tp->next_module;
-		unregister_netdev(root_tulip_dev);
-		release_region(root_tulip_dev->base_addr,
-					   tulip_tbl[tp->chip_id].io_size);
-		kfree(root_tulip_dev);
-		root_tulip_dev = next_dev;
-	}
+	pci_unregister_driver(&tulip_ops);
 }
 
-#endif  /* MODULE */
+module_init(tulip_init);
+module_exit(tulip_cleanup);
 
 /*
  * Local variables:
diff -u --recursive --new-file v2.3.38/linux/drivers/net/tlan.c linux/drivers/net/tlan.c
--- v2.3.38/linux/drivers/net/tlan.c	Mon Dec 20 18:48:21 1999
+++ linux/drivers/net/tlan.c	Sat Jan  8 12:57:53 2000
@@ -1,4 +1,4 @@
-/********************************************************************
+/*******************************************************************************
  *
  *  Linux ThunderLAN Driver
  *
@@ -7,6 +7,7 @@
  *
  *  (C) 1997-1998 Caldera, Inc.
  *  (C) 1998 James Banks
+ *  (C) 1999, 2000 Torben Mathiasen
  *
  *  This software may be used and distributed according to the terms
  *  of the GNU Public License, incorporated herein by reference.
@@ -34,12 +35,21 @@
  *      
  *	Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
  *
- *	v1.1 Dec 20 --	Removed linux version checking(patch from 
- *			Tigran Aivazian). v1.1 includes Alan's SMP
- *			opdates. We still have problems on SMP though,
- *			but I'm looking into that. 
+ *	v1.1 Dec 20, 1999    - Removed linux version checking
+ *			       Patch from Tigran Aivazian. 
+ *			     - v1.1 includes Alan's SMP updates.
+ *			     - We still have problems on SMP though,
+ *			       but I'm looking into that. 
+ *			
+ *	v1.2 Jan 02, 2000    - Hopefully fixed the SMP deadlock.
+ *			     - Removed dependency of HZ being 100.
+ *			     - We now allow higher priority timers to 
+ *			       overwrite timers like TLAN_TIMER_ACTIVITY
+ *			       Patch from John Cagle <john.cagle@compaq.com>.
+ *			     - Fixed a few compiler warnings.
+ *			     
  *
- ********************************************************************/
+ *******************************************************************************/
 
 
 #include <linux/module.h>
@@ -81,7 +91,7 @@
 static	u8		*TLanPadBuffer;
 static	char		TLanSignature[] = "TLAN";
 static	int		TLanVersionMajor = 1;
-static	int		TLanVersionMinor = 1;
+static	int		TLanVersionMinor = 2;
 
 
 static	TLanAdapterEntry TLanAdapterList[] = {
@@ -244,7 +254,8 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&priv->lock, flags);
-	if ( priv->timer.function != NULL ) {
+	if ( priv->timer.function != NULL &&
+		priv->timerType != TLAN_TIMER_ACTIVITY) {
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return;
 	}
@@ -1160,7 +1171,12 @@
 	if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
 		TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
 		if ( priv->timer.function == NULL ) {
-			TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+			 priv->timer.function = &TLan_Timer;
+			 priv->timer.data = (unsigned long) dev;
+			 priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+			 priv->timerSetAt = jiffies;
+			 priv->timerType = TLAN_TIMER_ACTIVITY;
+			 add_timer(&priv->timer);
 		} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
 			priv->timerSetAt = jiffies;
 		}
@@ -1316,7 +1332,12 @@
 	if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
 		TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
 		if ( priv->timer.function == NULL )  {
-			TLan_SetTimer( dev, TLAN_TIMER_ACT_DELAY, TLAN_TIMER_ACTIVITY );
+			priv->timer.function = &TLan_Timer;
+			priv->timer.data = (unsigned long) dev;
+			priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY;
+			priv->timerSetAt = jiffies;
+			priv->timerType = TLAN_TIMER_ACTIVITY;
+			add_timer(&priv->timer);
 		} else if ( priv->timerType == TLAN_TIMER_ACTIVITY ) {
 			priv->timerSetAt = jiffies;
 		}
@@ -1554,7 +1575,7 @@
 	 *		for a short period to power up the LED so it
 	 *		can be seen.  This delay can be changed by
 	 *		changing the TLAN_TIMER_ACT_DELAY in tlan.h,
-	 *		if desired.  10 jiffies produces a slightly
+	 *		if desired.  100 ms  produces a slightly
 	 *		sluggish response.
 	 *
 	 **************************************************************/
@@ -1564,7 +1585,7 @@
 	struct net_device	*dev = (struct net_device *) data;
 	TLanPrivateInfo	*priv = (TLanPrivateInfo *) dev->priv;
 	u32		elapsed;
-	unsigned long	flags;
+	unsigned long	flags = 0;
 
 	priv->timer.function = NULL;
 
@@ -2203,11 +2224,11 @@
 		TLan_MiiWriteReg( dev, priv->phy[1], MII_GEN_CTL, value );
 	}
 
-	/* Wait for 5 jiffies (50 ms) and powerup
+	/* Wait for 50 ms and powerup
 	 * This is abitrary.  It is intended to make sure the
 	 * tranceiver settles.
 	 */
-	TLan_SetTimer( dev, 5, TLAN_TIMER_PHY_PUP );
+	TLan_SetTimer( dev, (50/(1000/HZ)), TLAN_TIMER_PHY_PUP );
 
 } /* TLan_PhyPowerDown */
 
@@ -2224,11 +2245,11 @@
 	value = MII_GC_LOOPBK;
 	TLan_MiiWriteReg( dev, priv->phy[priv->phyNum], MII_GEN_CTL, value );
 
-	/* Wait for 50 jiffies (500 ms) and reset the
+	/* Wait for 500 ms and reset the
 	 * tranceiver.  The TLAN docs say both 50 ms and
 	 * 500 ms, so do the longer, just in case
 	 */
-	TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_RESET );
+	TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_RESET );
 
 } /* TLan_PhyPowerUp */
 
@@ -2253,10 +2274,10 @@
 	}
 	TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0 );
 
-	/* Wait for 50 jiffies (500 ms) and initialize.
+	/* Wait for 500 ms and initialize.
 	 * I don't remember why I wait this long.
 	 */
-	TLan_SetTimer( dev, 50, TLAN_TIMER_PHY_START_LINK );
+	TLan_SetTimer( dev, (HZ/2), TLAN_TIMER_PHY_START_LINK );
 
 } /* TLan_PhyReset */
 
@@ -2299,13 +2320,13 @@
        		TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1000 );
 		TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x1200 );
 
-		/* Wait for 400 jiffies (4 sec) for autonegotiation
+		/* Wait for 4 sec for autonegotiation
 		 * to complete.  The max spec time is less than this
 		 * but the card need additional time to start AN.
 		 * .5 sec should be plenty extra.
 		 */
 		printk( "TLAN:  %s: Starting autonegotiation.\n", dev->name );
-		TLan_SetTimer( dev, 400, TLAN_TIMER_PHY_FINISH_AN );
+		TLan_SetTimer( dev, (4*HZ), TLAN_TIMER_PHY_FINISH_AN );
 		return;
 	}
 
@@ -2334,10 +2355,10 @@
         	TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tctl );
 	}
 
-	/* Wait for 100 jiffies (1 sec) to give the tranceiver time
+	/* Wait for 1 sec to give the tranceiver time
 	 * to establish link.
 	 */
-	TLan_SetTimer( dev, 100, TLAN_TIMER_FINISH_RESET );
+	TLan_SetTimer( dev, HZ, TLAN_TIMER_FINISH_RESET );
 
 } /* TLan_PhyStartLink */
 
@@ -2358,11 +2379,11 @@
 
 	TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
 	if ( ! ( status & MII_GS_AUTOCMPLT ) ) {
-		/* Wait for 800 jiffies (8 sec) to give the process
+		/* Wait for 8 sec to give the process
 		 * more time.  Perhaps we should fail after a while.
 		 */
 		printk( "TLAN:  Giving autonegotiation more time.\n" );
-		TLan_SetTimer( dev, 800, TLAN_TIMER_PHY_FINISH_AN );
+		TLan_SetTimer( dev, (8*HZ), TLAN_TIMER_PHY_FINISH_AN );
 		return;
 	}
 
@@ -2394,9 +2415,9 @@
 		}
 	}
 
-	/* Wait for 10 jiffies (100 ms).  No reason in partiticular.
+	/* Wait for 100 ms.  No reason in partiticular.
 	 */
-	TLan_SetTimer( dev, 10, TLAN_TIMER_FINISH_RESET );
+	TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET );
 		
 } /* TLan_PhyFinishAutoNeg */
 
@@ -2447,7 +2468,7 @@
 	int	err;
 	int	minten;
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-	unsigned long flags;
+	unsigned long flags = 0;
 
 	err = FALSE;
 	outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
@@ -2616,7 +2637,7 @@
 {
 	u16	sio;
 	int	minten;
-	unsigned long flags;
+	unsigned long flags = 0;
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
 
 	outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
@@ -2847,7 +2868,7 @@
 {
 	int err;
 	TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv;
-	unsigned long flags;
+	unsigned long flags = 0;
 	int ret=0;
 
 	if ( dev->interrupt == 0 )
diff -u --recursive --new-file v2.3.38/linux/drivers/net/tlan.h linux/drivers/net/tlan.h
--- v2.3.38/linux/drivers/net/tlan.h	Mon Dec 20 18:48:21 1999
+++ linux/drivers/net/tlan.h	Sat Jan  8 12:57:53 2000
@@ -8,7 +8,8 @@
  *  by James Banks
  *
  *  (C) 1997-1998 Caldera, Inc.
- *
+ *  (C) 1999-2000 Torben Mathiasen
+ * 
  *  This software may be used and distributed according to the terms
  *  of the GNU Public License, incorporated herein by reference.
  *
@@ -206,7 +207,7 @@
 #define TLAN_TIMER_PHY_FINISH_AN	7
 #define TLAN_TIMER_FINISH_RESET		8
 
-#define TLAN_TIMER_ACT_DELAY		10
+#define TLAN_TIMER_ACT_DELAY		(HZ/10)
 
 
 
diff -u --recursive --new-file v2.3.38/linux/drivers/net/wan/cycx_drv.c linux/drivers/net/wan/cycx_drv.c
--- v2.3.38/linux/drivers/net/wan/cycx_drv.c	Thu Nov 18 20:25:37 1999
+++ linux/drivers/net/wan/cycx_drv.c	Sat Jan  8 21:36:20 2000
@@ -1,13 +1,13 @@
 /*
 * cycx_drv.c	Cyclom 2X Support Module.
 *
-*		This module is a library of common hardware-specific
+*		This module is a library of common hardware specific
 *		functions used by the Cyclades Cyclom 2X sync card.
 *
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
+* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
+*
 * Based on sdladrv.c by Gene Kozin <genek@compuserve.com>
 *
 *		This program is free software; you can redistribute it and/or
@@ -15,15 +15,16 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* 1999/11/11	acme		set_current_state(TASK_INTERRUPTIBLE), code cleanup
+* 1999/11/11	acme		set_current_state(TASK_INTERRUPTIBLE), code
+*				cleanup
 * 1999/11/08	acme		init_cyc2x deleted, doing nothing
 * 1999/11/06	acme		back to read[bw], write[bw] and memcpy_to and
 *				fromio to use dpmbase ioremaped
-* 1999/10/26	acme		use isa_read[bw], isa_write[bw] and isa_memcpy_to
-*				and fromio
+* 1999/10/26	acme		use isa_read[bw], isa_write[bw] & isa_memcpy_to
+*				& fromio
 * 1999/10/23	acme		cleanup to only supports cyclom2x: all the other
-*				boards are no longer manufactured by cyclades, if
-*				someone wants to support them... be my guest!
+*				boards are no longer manufactured by cyclades,
+*				if someone wants to support them... be my guest!
 * 1999/05/28    acme		cycx_intack & cycx_intde gone for good
 * 1999/05/18	acme		lots of unlogged work, submitting to Linus...
 * 1999/01/03	acme		more judicious use of data types
@@ -65,7 +66,7 @@
 #include <asm/io.h>		/* read[wl], write[wl], ioremap, iounmap */
 
 #define	MOD_VERSION	0
-#define	MOD_RELEASE	4
+#define	MOD_RELEASE	5
 
 #ifdef MODULE
 MODULE_AUTHOR("Arnaldo Carvalho de Melo");
@@ -103,7 +104,8 @@
 /* private data */
 static char modname[] = "cycx_drv";
 static char fullname[] = "Cyclom 2X Support Module";
-static char copyright[]	= "(c) 1998, 1999 Arnaldo Carvalho de Melo";
+static char copyright[] = "(c) 1998-2000 Arnaldo Carvalho de Melo "
+			  "<acme@conectiva.com.br>";
 
 /* Hardware configuration options.
  * These are arrays of configuration options used by verification routines.
@@ -130,8 +132,9 @@
 #ifdef MODULE
 int init_module(void)
 {
-	printk(KERN_INFO "%s v%u.%u %s\n",
-		fullname, MOD_VERSION, MOD_RELEASE, copyright);
+	printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE,
+			 copyright);
+
 	return 0;
 }
 /* Module 'remove' entry point.
@@ -198,6 +201,7 @@
 int cycx_down(cycxhw_t *hw)
 {
 	iounmap((u32 *)hw->dpmbase);
+
 	return 0;
 }
 
@@ -226,7 +230,9 @@
 
 	while (cyc2x_readw(addr)) {
 		udelay(1000);
-		if (++i > 50) return -1;
+		
+		if (++i > 50)
+			return -1;
 	}
 
 	return 0;
@@ -271,7 +277,8 @@
 		cyc2x_writew(TEST_PATTERN, addr + 0x10);
 
 		if (cyc2x_readw(addr + 0x10) == TEST_PATTERN)
-			if (cyc2x_readw(addr + 0x10) == TEST_PATTERN) return 1;
+			if (cyc2x_readw(addr + 0x10) == TEST_PATTERN)
+				return 1;
 
 		delay_cycx(1);
 	}
@@ -298,6 +305,7 @@
 {
 	cyc2x_memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
 	cyc2x_writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
+
 	return wait_cyc(addr);
 }
 
@@ -434,38 +442,39 @@
 	if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
 */
 	if (cksum != cfm->checksum) {
-		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware corrupted!\n", modname);
+		printk(KERN_ERR "%s:" __FUNCTION__ ": firmware corrupted!\n",
+				modname);
 		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
-                       len - sizeof(cfm_t) - 1, cfm->info.codesize);
+				len - sizeof(cfm_t) - 1, cfm->info.codesize);
                 printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
-                       cksum, cfm->checksum);
+				cksum, cfm->checksum);
 		return -EINVAL;
 	}
 
 	/* If everything is ok, set reset, data and code pointers */
 
-	img_hdr = (cycx_header_t*)(((u8*) cfm) + sizeof(cfm_t) - 1);
+	img_hdr = (cycx_header_t*)(((u8*)cfm) + sizeof(cfm_t) - 1);
 #ifdef FIRMWARE_DEBUG
 	printk(KERN_INFO "%s:" __FUNCTION__ ": image sizes\n", modname);
 	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
 	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
 	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
 #endif
-	reset_image = ((u8 *) img_hdr) + sizeof(cycx_header_t);
+	reset_image = ((u8 *)img_hdr) + sizeof(cycx_header_t);
 	data_image = reset_image + img_hdr->reset_size;
 	code_image = data_image + img_hdr->data_size;
 
 	/*---- Start load ----*/
         /* Announce */
 	printk(KERN_INFO "%s: loading firmware %s (ID=%u)...\n", modname,
-		(cfm->descr[0] != '\0') ? cfm->descr : "unknown firmware",
-		cfm->info.codeid);
+			 cfm->descr[0] ? cfm->descr : "unknown firmware",
+			 cfm->info.codeid);
 
 	for (i = 0 ; i < 5 ; i++) {
 		/* Reset Cyclom hardware */
 		if (!reset_cyc2x(hw->dpmbase)) {
-			printk(KERN_ERR "%s: dpm problem or board not "
-					"found.\n", modname);
+			printk(KERN_ERR "%s: dpm problem or board not found\n",
+					modname);
 			return -EINVAL;
 		}
 
@@ -536,6 +545,7 @@
 static int detect_cyc2x(u32 addr)
 {
 	reset_cyc2x(addr);
+
 	return memory_exists(addr);
 }
 
@@ -560,6 +570,7 @@
 	delay_cycx(2);
 	cyc2x_writeb(0, addr + RST_DISABLE);
 	delay_cycx(2);
+
 	return memory_exists(addr);
 }
 
diff -u --recursive --new-file v2.3.38/linux/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c
--- v2.3.38/linux/drivers/net/wan/cycx_main.c	Thu Nov 18 20:25:37 1999
+++ linux/drivers/net/wan/cycx_main.c	Sat Jan  8 21:36:20 2000
@@ -3,7 +3,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
 *
 * Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
 *			 Jaspreet Singh	<jaspreet@sangoma.com>
@@ -13,6 +13,7 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* 2000/01/08	acme		cleanup
 * 1999/11/06	acme		cycx_down back to life (it needs to be
 *				called to iounmap the dpmbase)
 * 1999/08/09	acme		removed references to enable_tx_int
@@ -48,7 +49,7 @@
 /* Defines & Macros */
 
 #define	DRV_VERSION	0		/* version number */
-#define	DRV_RELEASE	4		/* release (minor version) number */
+#define	DRV_RELEASE	5		/* release (minor version) number */
 #define	MAX_CARDS	1		/* max number of adapters */
 
 #ifndef	CONFIG_CYCLOMX_CARDS		/* configurable option */
@@ -76,7 +77,8 @@
 /* private data */
 static char drvname[]	= "cyclomx";
 static char fullname[]	= "CYCLOM 2X(tm) Sync Card Driver";
-static char copyright[]	= "(c) 1998, 1999 Arnaldo Carvalho de Melo";
+static char copyright[] = "(c) 1998-2000 Arnaldo Carvalho de Melo "
+			  "<acme@conectiva.com.br>";
 static int ncards = CONFIG_CYCLOMX_CARDS;
 static cycx_t *card_array = NULL;	/* adapter data space */
 
@@ -88,7 +90,7 @@
  * o allocate adapter data space
  * o initialize static data
  * o register all cards with WAN router
- * o calibrate CYCX shared memory access delay.
+ * o calibrate Cyclom 2X shared memory access delay.
  *
  * Return:	0	Ok
  *		< 0	error.
@@ -110,7 +112,8 @@
 	ncards = max(ncards, 1);
 	card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL);
 
-	if (card_array == NULL) return -ENOMEM;
+	if (!card_array)
+		return -ENOMEM;
 
 	memset(card_array, 0, sizeof(cycx_t) * ncards);
 
@@ -136,7 +139,8 @@
 		}
 	}
 
-	if (cnt) ncards = cnt;	/* adjust actual number of cards */
+	if (cnt)
+		ncards = cnt;	/* adjust actual number of cards */
 	else {
 		kfree(card_array);
 		err = -ENODEV;
@@ -165,13 +169,12 @@
 #endif
 /* WAN Device Driver Entry Points */
 /*
- * Setup/confugure WAN link driver.
+ * Setup/configure WAN link driver.
  * o check adapter state
  * o make sure firmware is present in configuration
  * o allocate interrupt vector
- * o setup CYCLOM X hardware
+ * o setup Cyclom 2X hardware
  * o call appropriate routine to perform protocol-specific initialization
- * o mark I/O region as used
  *
  * This function is called when router handles ROUTER_SETUP IOCTL. The
  * configuration structure is in kernel memory (including extended data, if
@@ -184,13 +187,15 @@
 	int irq;
 
 	/* Sanity checks */
-	if (!wandev || !wandev->private || !conf) return -EFAULT;
+	if (!wandev || !wandev->private || !conf)
+		return -EFAULT;
 
 	card = wandev->private;
 
-	if (wandev->state != WAN_UNCONFIGURED) return -EBUSY;
+	if (wandev->state != WAN_UNCONFIGURED)
+		return -EBUSY;
 
-	if (!conf->data_size || (conf->data == NULL)) {
+	if (!conf->data_size || !conf->data) {
 		printk(KERN_ERR "%s: firmware not found in configuration "
 				"data!\n", wandev->name);
 		return -EINVAL;
@@ -213,7 +218,7 @@
 
 	/* Configure hardware, load firmware, etc. */
 	memset(&card->hw, 0, sizeof(cycxhw_t));
-	card->hw.irq = (conf->irq == 9) ? 2 : conf->irq;
+	card->hw.irq = irq;
 	card->hw.dpmbase = conf->maddr;
 	card->hw.dpmsize = CYCX_WINDOWSIZE;
 	card->hw.fwid = CFID_X25_2X;
@@ -230,7 +235,7 @@
 		return err;
 	}
 
-	/* Intialize WAN device data space */
+	/* Initialize WAN device data space */
 	wandev->irq       = irq;
 	wandev->dma       = wandev->ioport = 0;
 	wandev->maddr     = (unsigned long*)card->hw.dpmbase;
@@ -241,7 +246,9 @@
 	/* Protocol-specific initialization */
 	switch (card->hw.fwid) {
 #ifdef CONFIG_CYCLOMX_X25
-		case CFID_X25_2X: err = cyx_init(card, conf); break;
+		case CFID_X25_2X:
+			err = cyx_init(card, conf);
+			break;
 #endif
 		default:
 			printk(KERN_ERR "%s: this firmware is not supported!\n",
@@ -271,15 +278,19 @@
 	cycx_t *card;
 
 	/* sanity checks */
-	if (!wandev || !wandev->private) return -EFAULT;
+	if (!wandev || !wandev->private)
+		return -EFAULT;
 
-	if (wandev->state == WAN_UNCONFIGURED) return 0;
+	if (wandev->state == WAN_UNCONFIGURED)
+		return 0;
 
 	card = wandev->private;
 	wandev->state = WAN_UNCONFIGURED;
 	cycx_down(&card->hw);
-	printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name, wandev->irq);
+	printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,
+			wandev->irq);
 	free_irq(wandev->irq, card);
+
 	return 0;
 }
 
@@ -289,7 +300,9 @@
  * o perform requested action
  *
  * This function is called when router handles one of the reserved user
- * IOCTLs.  Note that 'arg' stil points to user address space.
+ * IOCTLs.  Note that 'arg' still points to user address space.
+ *
+ * no reserved ioctls for the cyclom 2x up to now
  */
 static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg)
 {
@@ -298,8 +311,8 @@
 
 /* Miscellaneous */
 /*
- * CYCX Interrupt Service Routine.
- * o acknowledge CYCX hardware interrupt.
+ * Cyclom 2X Interrupt Service Routine.
+ * o acknowledge Cyclom 2X hardware interrupt.
  * o call protocol-specific interrupt service routine, if any.
  */
 static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs)
@@ -347,27 +360,22 @@
 void cyclomx_set_state (cycx_t *card, int state)
 {
 	unsigned long host_cpu_flags;
+	char *string_state = NULL;
 
 	spin_lock_irqsave(&card->lock, host_cpu_flags);
 
 	if (card->wandev.state != state) {
 		switch (state) {
 			case WAN_CONNECTED:
-				printk (KERN_INFO "%s: link connected!\n",
-						  card->devname);
-				break;
-
-			case WAN_CONNECTING:
-				printk (KERN_INFO "%s: link connecting...\n",
-						  card->devname);
+				string_state = "connected!";
 				break;
 
 			case WAN_DISCONNECTED:
-				printk (KERN_INFO "%s: link disconnected!\n",
-						  card->devname);
+				string_state = "disconnected!";
 				break;
 		}
 
+		printk(KERN_INFO "%s: link %s\n", card->devname, string_state);
 		card->wandev.state = state;
 	}
 
diff -u --recursive --new-file v2.3.38/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c
--- v2.3.38/linux/drivers/net/wan/cycx_x25.c	Mon Nov  1 13:56:26 1999
+++ linux/drivers/net/wan/cycx_x25.c	Sat Jan  8 21:36:20 2000
@@ -1,8 +1,9 @@
 /*
-* cycx_x25.c	CYCLOM X WAN Link Driver.  X.25 module.
+* cycx_x25.c	Cyclom 2X WAN Link Driver.  X.25 module.
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
 *
 * Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
 *
@@ -11,7 +12,8 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* 1999/10/27	acme		use ARPHRD_HWX25 so that the x25 stack know
+* 2000/01/08	acme		cleanup
+* 1999/10/27	acme		use ARPHRD_HWX25 so that the X.25 stack know
 *				that we have a X.25 stack implemented in
 *				firmware onboard
 * 1999/10/18	acme		support for X.25 sockets in if_send,
@@ -35,7 +37,7 @@
 *				AFAIT, with ARPHRD_ETHER). This seems to be
 *				needed to use socket(AF_X25)...
 *				Now the config file must specify a peer media
-*				address for svc channes over a crossover cable.
+*				address for svc channels over a crossover cable.
 *				Removed hold_timeout from x25_channel_t,
 *				not used.
 *				A little enhancement in the DEBUG processing
@@ -79,7 +81,7 @@
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <linux/if_arp.h>       /* ARPHRD_HWX25 */
-#include <linux/cyclomx.h>	/* CYCLOM X common user API definitions */
+#include <linux/cyclomx.h>	/* Cyclom 2X common user API definitions */
 #include <linux/cycx_x25.h>	/* X.25 firmware API definitions */
 
 /* Defines & Macros */
@@ -87,7 +89,7 @@
 #define X25_CHAN_MTU	2048	/* unfragmented logical channel MTU */
 
 /* Data Structures */
-/* This is an extention of the 'struct net_device' we create for each network
+/* This is an extension of the 'struct net_device' we create for each network
    interface to keep the rest of X.25 channel-specific data. */
 typedef struct x25_channel {
 	char name[WAN_IFNAME_SZ+1];	/* interface name, ASCIIZ */
@@ -110,7 +112,8 @@
 /* Function Prototypes */
 /* WAN link driver entry points. These are called by the WAN router module. */
 static int update (wan_device_t *wandev),
-	   new_if (wan_device_t *wandev, struct net_device *dev,wanif_conf_t *conf),
+	   new_if (wan_device_t *wandev, struct net_device *dev,
+		   wanif_conf_t *conf),
 	   del_if (wan_device_t *wandev, struct net_device *dev);
 
 /* Network device interface */
@@ -139,7 +142,8 @@
 /* X.25 firmware interface functions */
 static int x25_configure (cycx_t *card, TX25Config *conf),
 	   x25_get_stats (cycx_t *card),
-	   x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,void *buf),
+	   x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,
+		     void *buf),
 	   x25_connect_response (cycx_t *card, x25_channel_t *chan),
 	   x25_disconnect_response (cycx_t *card, u8 link, u8 lcn);
 
@@ -182,7 +186,7 @@
 
 /* X.25 Protocol Initialization routine.
  *
- * This routine is called by the main CYCLOM X module during setup.  At this
+ * This routine is called by the main Cyclom 2X 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
@@ -206,7 +210,7 @@
 	card->u.x.connection_keys = 0;
 	card->u.x.lock = SPIN_LOCK_UNLOCKED;
 
-	/* Configure adapter. Here we set resonable defaults, then parse
+	/* Configure adapter. Here we set reasonable 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
@@ -302,6 +306,7 @@
 	card->wandev.new_if	= new_if;
 	card->wandev.del_if	= del_if;
 	card->wandev.state	= WAN_DISCONNECTED;
+
 	return 0;
 }
 
@@ -317,6 +322,7 @@
 		return -ENODEV;
 
 	x25_get_stats(wandev->private);
+
 	return 0;
 }
 
@@ -326,7 +332,7 @@
  * 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.
+ * o prepare network device structure for registration.
  *
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created) */
@@ -380,7 +386,7 @@
                 strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
 		init_timer(&chan->timer);
 		chan->timer.function = chan_timer;
-		chan->timer.data = (unsigned long) dev;
+		chan->timer.data = (unsigned long)dev;
 
                 /* Set channel timeouts (default if not specified) */
                 chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
@@ -413,6 +419,7 @@
 	dev->name = chan->name;
 	dev->init = if_init;
 	dev->priv = chan;
+
 	return 0;
 }
 
@@ -480,6 +487,7 @@
 	/* Initialize socket buffers */
 	dev_init_buffers(dev);
 	set_chan_state(dev, WAN_DISCONNECTED);
+
 	return 0;
 }
 
@@ -518,6 +526,7 @@
 		chan_disconnect(dev);
 		
 	cyclomx_close(card);
+
 	return 0;
 }
 
@@ -533,6 +542,7 @@
 		      u16 type, void *daddr, void *saddr, unsigned len)
 {
 	skb->protocol = type;
+
 	return dev->hard_header_len;
 }
 
@@ -632,6 +642,7 @@
 
 free_packet:
 	dev_kfree_skb(skb);
+
 	return 0;
 }
 
@@ -710,7 +721,7 @@
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
 
 	/* unbusy device and then dev_tint(); */
-	if ((dev = get_dev_by_lcn (wandev, lcn)) != NULL) {
+	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
 		card->buff_int_mode_unbusy = 1;
 		dev->tbusy = 0;
 	} else
@@ -721,14 +732,14 @@
 /* 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 map logical 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
- *    comming and we have to allocate buffer for the maximum IP packet size
+ *    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. */
@@ -884,7 +895,7 @@
 	set_chan_state(dev, WAN_CONNECTED);
 }
 
-/* Disonnect confirm interrupt handler. */
+/* Disconnect confirm interrupt handler. */
 static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
 {
 	wan_device_t *wandev = &card->wandev;
@@ -934,7 +945,7 @@
 	cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));
 	cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));
 	cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));
-	/* at most 20 bytes are available... thanx to Daniela :) */
+	/* at most 20 bytes are available... thanks to Daniela :) */
 	toread = size < 20 ? size : 20;
 	cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);
 	cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
@@ -987,8 +998,9 @@
 	printk(KERN_INFO "%s: %s\n", msg, hex);
 }
 #endif
-/* CYCLOM X Firmware-Specific Functions */
-/* Exec x25 command. */
+
+/* Cyclom 2X Firmware-Specific Functions */
+/* Exec X.25 command. */
 static int x25_exec (cycx_t *card, int command, int link,
 		     void *d1, int len1, void *d2, int len2)
 {
@@ -1007,7 +1019,7 @@
 	/* write command */
 	cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));
 
-	/* write x25 data */
+	/* write X.25 data */
 	if (d1) {
 		cycx_poke(&card->hw, addr, d1, len1);
 
@@ -1016,7 +1028,7 @@
 				u32 addr1 = 0xA00 + 0x400 * link;
 
 				cycx_poke(&card->hw, addr + len1, d2, 249);
-				cycx_poke(&card->hw, addr1, ((u8*) d2) + 249,
+				cycx_poke(&card->hw, addr1, ((u8*)d2) + 249,
 					  len2 - 249);
 			} else
 				cycx_poke(&card->hw, addr + len1, d2, len2);
@@ -1069,7 +1081,7 @@
 static int x25_get_stats (cycx_t *card)
 {
 	/* the firmware expects 20 in the size field!!!
-	   thanx to Daniela */
+	   thanks to Daniela */
 	int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);
 
 	if (err)
@@ -1095,6 +1107,7 @@
 	card->wandev.stats.tx_errors = 0; /* not available from fw */
 
 	x25_dump_devs(&card->wandev);
+
 	return 0;
 }
 
@@ -1180,7 +1193,7 @@
 		++len;
 
 	d[5] = mylen << 4 | remotelen;
-	d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanx to Daniela :) */
+	d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */
 	
 	if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
 			    &d, 7 + len + 1, NULL, 0)) != 0)
@@ -1200,7 +1213,7 @@
 	d[0] = d[3] = chan->lcn;
 	d[2] = 0x10;
 	d[4] = 0x0F;
-	d[7] = 0xCC; /* TCP/IP over X.25, thanx Daniela */
+	d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */
 
 	return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);
 }
@@ -1214,6 +1227,7 @@
 	d[0] = d[3] = lcn;
 	d[2] = 0x10;
 	d[4] = 0x17;
+
 	return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);
 }
 
@@ -1252,6 +1266,7 @@
 	for (; dev; dev = dev->slave)
 		if (((x25_channel_t*)dev->priv)->lcn == lcn)
 			break;
+	
 	return dev;
 }
 
@@ -1261,8 +1276,9 @@
 	struct net_device *dev = wandev->dev;
 
 	for (; dev; dev = dev->slave)
-		if (!strcmp (((x25_channel_t*)dev->priv)->addr, dte))
+		if (!strcmp(((x25_channel_t*)dev->priv)->addr, dte))
 			break;
+
 	return dev;
 }
 
@@ -1281,10 +1297,13 @@
 	if (chan->svc) {
                 if (!chan->addr[0])
 			return -EINVAL; /* no destination address */
+
                 dprintk(KERN_INFO "%s: placing X.25 call to %s...\n",
 				  card->devname, chan->addr);
+
                 if (x25_place_call(card, chan))
 			return -EIO;
+
                 set_chan_state(dev, WAN_CONNECTING);
                 return 1;
         } else 
@@ -1309,18 +1328,14 @@
 /* Called by kernel timer */
 static void chan_timer (unsigned long d)
 {
-	struct net_device *dev = (struct net_device*) d;
+	struct net_device *dev = (struct net_device *)d;
 	x25_channel_t *chan = dev->priv;
 	
-	switch (chan->state) {
-		case WAN_CONNECTED:
-			chan_disconnect(dev);
-			break;
-		default:
-			printk (KERN_ERR "%s: chan_timer for svc (%s) not "
-					 "connected!\n",
-					 chan->card->devname, dev->name);
-	}
+	if (chan->state == WAN_CONNECTED)
+		chan_disconnect(dev);
+	else
+		printk(KERN_ERR "%s: chan_timer for svc (%s) not connected!\n",
+				chan->card->devname, dev->name);
 }
 
 /* Set logical channel state. */
@@ -1329,6 +1344,7 @@
 	x25_channel_t *chan = dev->priv;
 	cycx_t *card = chan->card;
 	u32 flags = 0;
+	char *string_state = NULL;
 
 	spin_lock_irqsave(&card->lock, flags);
 
@@ -1338,9 +1354,7 @@
 	
 		switch (state) {
 			case WAN_CONNECTED:
-				printk (KERN_INFO "%s: interface %s "
-						  "connected!\n",
-						  card->devname, dev->name);
+				string_state = "connected!";
 				*(u16*)dev->dev_addr = htons(chan->lcn);
 				dev->tbusy = 0;
 				reset_timer(dev);
@@ -1351,21 +1365,16 @@
 				break;
 
 			case WAN_CONNECTING:
-				printk (KERN_INFO "%s: interface %s "
-						  "connecting...\n",
-						  card->devname, dev->name);
+				string_state = "connecting...";
 				break;
 
 			case WAN_DISCONNECTING:
-				printk (KERN_INFO "%s: interface %s "
-						  "disconnecting...\n",
-						  card->devname, dev->name);
+				string_state = "disconnecting...";
 				break;
 
 			case WAN_DISCONNECTED:
-				printk (KERN_INFO "%s: interface %s "
-						  "disconnected!\n",
-						  card->devname, dev->name);
+				string_state = "disconnected!";
+				
 				if (chan->svc) {
 					*(unsigned short*)dev->dev_addr = 0;
 					chan->lcn = 0;
@@ -1378,6 +1387,8 @@
 				break;
 		}
 
+		printk (KERN_INFO "%s: interface %s %s\n", card->devname,
+				  dev->name, string_state);
 		chan->state = state;
 	}
 
@@ -1419,6 +1430,7 @@
 
 	++chan->ifstats.tx_packets;
 	chan->ifstats.tx_bytes += len;
+
 	return 0;
 }
 
@@ -1488,7 +1500,7 @@
 		len = strlen(str);
 
 	for (; len && is_digit(*str); ++str, --len)
-		val = (val * 10) + (*str - (unsigned)'0');
+		val = (val * 10) + (*str - (unsigned) '0');
 
 	return val;
 }
@@ -1497,66 +1509,65 @@
 {
 	x25_channel_t *chan = dev->priv;
 
-	if (!chan->svc)
-		return;
-
-	del_timer(&chan->timer);
-	chan->timer.expires = jiffies + chan->idle_tmout * HZ;
-	add_timer(&chan->timer);
+	if (chan->svc) {
+		del_timer(&chan->timer);
+		chan->timer.expires = jiffies + chan->idle_tmout * HZ;
+		add_timer(&chan->timer);
+	}
 }
 #ifdef CYCLOMX_X25_DEBUG
 static void x25_dump_config(TX25Config *conf)
 {
-	printk (KERN_INFO "x25 configuration\n");
-	printk (KERN_INFO "-----------------\n");
-        printk (KERN_INFO "link number=%d\n", conf->link);
-        printk (KERN_INFO "line speed=%d\n", conf->speed);
-        printk (KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
-        printk (KERN_INFO "# level 2 retransm.=%d\n", conf->n2);
-        printk (KERN_INFO "level 2 window=%d\n", conf->n2win);
-        printk (KERN_INFO "level 3 window=%d\n", conf->n3win);
-        printk (KERN_INFO "# logical channels=%d\n", conf->nvc);
-        printk (KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);
-	printk (KERN_INFO "my address=%d\n", conf->locaddr);
-        printk (KERN_INFO "remote address=%d\n", conf->remaddr);
-        printk (KERN_INFO "t1=%d seconds\n", conf->t1);
-        printk (KERN_INFO "t2=%d seconds\n", conf->t2);
-        printk (KERN_INFO "t21=%d seconds\n", conf->t21);
-        printk (KERN_INFO "# PVCs=%d\n", conf->npvc);
-	printk (KERN_INFO "t23=%d seconds\n", conf->t23);
-        printk (KERN_INFO "flags=0x%x\n", conf->flags);
+	printk(KERN_INFO "X.25 configuration\n");
+	printk(KERN_INFO "-----------------\n");
+	printk(KERN_INFO "link number=%d\n", conf->link);
+	printk(KERN_INFO "line speed=%d\n", conf->speed);
+	printk(KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");
+	printk(KERN_INFO "# level 2 retransm.=%d\n", conf->n2);
+	printk(KERN_INFO "level 2 window=%d\n", conf->n2win);
+	printk(KERN_INFO "level 3 window=%d\n", conf->n3win);
+	printk(KERN_INFO "# logical channels=%d\n", conf->nvc);
+	printk(KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);
+	printk(KERN_INFO "my address=%d\n", conf->locaddr);
+	printk(KERN_INFO "remote address=%d\n", conf->remaddr);
+	printk(KERN_INFO "t1=%d seconds\n", conf->t1);
+	printk(KERN_INFO "t2=%d seconds\n", conf->t2);
+	printk(KERN_INFO "t21=%d seconds\n", conf->t21);
+	printk(KERN_INFO "# PVCs=%d\n", conf->npvc);
+	printk(KERN_INFO "t23=%d seconds\n", conf->t23);
+	printk(KERN_INFO "flags=0x%x\n", conf->flags);
 }
 
 static void x25_dump_stats(TX25Stats *stats)
 {
-	printk (KERN_INFO "x25 statistics\n");
-	printk (KERN_INFO "--------------\n");
-        printk (KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);
-        printk (KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);
-        printk (KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);
-        printk (KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);
-        printk (KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);
-        printk (KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);
-        printk (KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);
-        printk (KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);
-        printk (KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);
-        printk (KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
+	printk(KERN_INFO "X.25 statistics\n");
+	printk(KERN_INFO "--------------\n");
+	printk(KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);
+	printk(KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);
+	printk(KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);
+	printk(KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);
+	printk(KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);
+	printk(KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);
+	printk(KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);
+	printk(KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);
+	printk(KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);
+	printk(KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
 }
 
 static void x25_dump_devs(wan_device_t *wandev)
 {
 	struct net_device *dev = wandev->dev;
 
-	printk (KERN_INFO "x25 dev states\n");
-	printk (KERN_INFO "name: addr:           tbusy:  protocol:\n");
-	printk (KERN_INFO "---------------------------------------\n");
+	printk(KERN_INFO "X.25 dev states\n");
+	printk(KERN_INFO "name: addr:           tbusy:  protocol:\n");
+	printk(KERN_INFO "---------------------------------------\n");
 
 	for (; dev; dev = dev->slave) {
 		x25_channel_t *chan = dev->priv;
 
-		printk (KERN_INFO "%-5.5s %-15.15s   %ld     ETH_P_%s\n",
-				  chan->name, chan->addr, dev->tbusy,
-				  chan->protocol == ETH_P_IP ? "IP" : "X25");
+		printk(KERN_INFO "%-5.5s %-15.15s   %ld     ETH_P_%s\n",
+				 chan->name, chan->addr, dev->tbusy,
+				 chan->protocol == ETH_P_IP ? "IP" : "X25");
 	}
 }
 
diff -u --recursive --new-file v2.3.38/linux/drivers/net/wan/z85230.c linux/drivers/net/wan/z85230.c
--- v2.3.38/linux/drivers/net/wan/z85230.c	Mon Oct 11 15:38:15 1999
+++ linux/drivers/net/wan/z85230.c	Sat Jan  8 12:54:55 2000
@@ -5,18 +5,18 @@
  *	2 of the License, or (at your option) any later version.
  *
  *	(c) Copyright 1998 Building Number Three Ltd
+ *	(c) Copyright 2000 Red Hat Software
  *
  *	Development of this driver was funded by Equiinet Ltd
  *			http://www.equiinet.com
  *
  *	ChangeLog:
  *
- *	Asynchronous mode dropped for 2.2. For 2.3 we will attempt the
+ *	Asynchronous mode dropped for 2.2. For 2.5 we will attempt the
  *	unification of all the Z85x30 asynchronous drivers for real.
  *
- *	To Do:
- *	
- *	Finish DMA mode support.
+ *	DMA now uses get_free_page as kmalloc buffers may span a 64K 
+ *	boundary.
  *
  *	Performance
  *
@@ -662,39 +662,28 @@
 	c->txdma_on = 0;
 	
 	/*
-	 *	Allocate the DMA flip buffers
+	 *	Allocate the DMA flip buffers. Limit by page size.
+	 *	Everyone runs 1500 mtu or less on wan links so this
+	 *	should be fine.
 	 */
 	 
-	c->rx_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	if(c->mtu  > PAGE_SIZE/2)
+		return -EMSGSIZE;
+	 
+	c->rx_buf[0]=get_free_page(GFP_KERNEL|GFP_DMA);
 	if(c->rx_buf[0]==NULL)
 		return -ENOBUFS;
-	c->rx_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->rx_buf[1]==NULL)
-	{
-		kfree(c->rx_buf[0]);
-		c->rx_buf[0]=NULL;
-		return -ENOBUFS;
-	}
+	c->rx_buf[1]=c->rx_buf[0]+PAGE_SIZE/2;
 	
-	c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	c->tx_dma_buf[0]=get_free_page(GFP_KERNEL|GFP_DMA);
 	if(c->tx_dma_buf[0]==NULL)
 	{
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
-		c->rx_buf[0]=NULL;
-		return -ENOBUFS;
-	}
-	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->tx_dma_buf[1]==NULL)
-	{
-		kfree(c->tx_dma_buf[0]);
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
+		free_page(c->rx_buf[0]);
 		c->rx_buf[0]=NULL;
-		c->rx_buf[1]=NULL;
-		c->tx_dma_buf[0]=NULL;
 		return -ENOBUFS;
 	}
+	c->tx_dma_buf[1]=c->tx_dma_buf[0]+PAGE_SIZE/2;
+
 	c->tx_dma_used=0;
 	c->dma_tx = 1;
 	c->dma_num=0;
@@ -806,24 +795,14 @@
 	
 	if(c->rx_buf[0])
 	{
-		kfree(c->rx_buf[0]);
+		free_page(c->rx_buf[0]);
 		c->rx_buf[0]=NULL;
 	}
-	if(c->rx_buf[1])
-	{
-		kfree(c->rx_buf[1]);
-		c->rx_buf[1]=NULL;
-	}
 	if(c->tx_dma_buf[0])
 	{
-		kfree(c->tx_dma_buf[0]);
+		free_page(c->tx_dma_buf[0]);
 		c->tx_dma_buf[0]=NULL;
 	}
-	if(c->tx_dma_buf[1])
-	{
-		kfree(c->tx_dma_buf[1]);
-		c->tx_dma_buf[1]=NULL;
-	}
 	chk=read_zsreg(c,R0);
 	write_zsreg(c, R3, c->regs[R3]);
 	z8530_rtsdtr(c,0);
@@ -857,25 +836,21 @@
 	c->rxdma_on = 0;
 	c->txdma_on = 0;
 	
-	c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
+	/*
+	 *	Allocate the DMA flip buffers. Limit by page size.
+	 *	Everyone runs 1500 mtu or less on wan links so this
+	 *	should be fine.
+	 */
+	 
+	if(c->mtu  > PAGE_SIZE/2)
+		return -EMSGSIZE;
+	 
+	c->tx_dma_buf[0]=get_free_page(GFP_KERNEL|GFP_DMA);
 	if(c->tx_dma_buf[0]==NULL)
-	{
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
-		c->rx_buf[0]=NULL;
 		return -ENOBUFS;
-	}
-	c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA);
-	if(c->tx_dma_buf[1]==NULL)
-	{
-		kfree(c->tx_dma_buf[0]);
-		kfree(c->rx_buf[0]);
-		kfree(c->rx_buf[1]);
-		c->rx_buf[0]=NULL;
-		c->rx_buf[1]=NULL;
-		c->tx_dma_buf[0]=NULL;
-		return -ENOBUFS;
-	}
+
+	c->tx_dma_buf[1] = c->tx_dma_buf[0] + PAGE_SIZE/2;
+
 	c->tx_dma_used=0;
 	c->dma_num=0;
 	c->dma_ready=1;
@@ -960,13 +935,8 @@
 	
 	if(c->tx_dma_buf[0])
 	{
-		kfree(c->tx_dma_buf[0]);
+		free_page(c->tx_dma_buf[0]);
 		c->tx_dma_buf[0]=NULL;
-	}
-	if(c->tx_dma_buf[1])
-	{
-		kfree(c->tx_dma_buf[1]);
-		c->tx_dma_buf[1]=NULL;
 	}
 	chk=read_zsreg(c,R0);
 	write_zsreg(c, R3, c->regs[R3]);
diff -u --recursive --new-file v2.3.38/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.3.38/linux/drivers/parport/parport_pc.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/parport/parport_pc.c	Mon Jan 10 12:20:11 2000
@@ -153,9 +153,7 @@
 	const struct parport_pc_private *priv = p->physport->private_data;
 
 	/* Prevent further data transfer. */
-	parport_frob_control (p,
-			      PARPORT_CONTROL_STROBE,
-			      PARPORT_CONTROL_STROBE);
+	frob_econtrol (p, 0xe0, ECR_TST << 5);
 
 	/* Adjust for the contents of the FIFO. */
 	for (residue = priv->fifo_depth; ; residue--) {
@@ -171,7 +169,6 @@
 
 	/* Reset the FIFO. */
 	frob_econtrol (p, 0xe0, ECR_PS2 << 5);
-	parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
 
 	/* Now change to config mode and clean up. FIXME */
 	frob_econtrol (p, 0xe0, ECR_CNF << 5);
@@ -500,7 +497,7 @@
 			ret = 0;
 			if (!time_before (jiffies, expire)) {
 				/* Timed out. */
-				printk (KERN_DEBUG "Timed out\n");
+				printk (KERN_DEBUG "FIFO write timed out\n");
 				break;
 			}
 			ecrval = inb (ECONTROL (port));
@@ -601,7 +598,7 @@
 		ret = 0;
 		if (!time_before (jiffies, expire)) {
 			/* Timed out. */
-			printk (KERN_DEBUG "Timed out\n");
+			printk (KERN_DEBUG "DMA write timed out\n");
 			break;
 		}
 		/* Is serviceIntr set? */
@@ -677,9 +674,7 @@
 		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
 
 		/* Prevent further data transfer. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_STROBE,
-				      PARPORT_CONTROL_STROBE);
+		frob_econtrol (port, 0xe0, ECR_TST << 5);
 
 		/* Adjust for the contents of the FIFO. */
 		for (written -= priv->fifo_depth; ; written++) {
@@ -692,9 +687,6 @@
 
 		/* Reset the FIFO and return to PS2 mode. */
 		frob_econtrol (port, 0xe0, ECR_PS2 << 5);
-
-		/* De-assert strobe. */
-		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 	}
 
 	parport_wait_peripheral (port,
@@ -748,9 +740,7 @@
 		printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
 
 		/* Prevent further data transfer. */
-		parport_frob_control (port,
-				      PARPORT_CONTROL_STROBE,
-				      PARPORT_CONTROL_STROBE);
+		frob_econtrol (port, 0xe0, ECR_TST);
 
 		/* Adjust for the contents of the FIFO. */
 		for (written -= priv->fifo_depth; ; written++) {
@@ -764,9 +754,6 @@
 		/* Reset the FIFO and return to PS2 mode. */
 		frob_econtrol (port, 0xe0, ECR_PS2 << 5);
 
-		/* De-assert strobe. */
-		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
-
 		/* Host transfer recovery. */
 		parport_pc_data_reverse (port); /* Must be in PS2 mode */
 		udelay (5);
@@ -878,7 +865,7 @@
 			ret = 0;
 			if (!time_before (jiffies, expire)) {
 				/* Timed out. */
-				printk (KERN_DEBUG "Timed out\n");
+				printk (KERN_DEBUG "PIO read timed out\n");
 				break;
 			}
 			ecrval = inb (ECONTROL (port));
diff -u --recursive --new-file v2.3.38/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.38/linux/drivers/pci/pci.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/pci/pci.c	Sat Jan  8 21:36:48 2000
@@ -9,6 +9,7 @@
  *	Copyright 1997 -- 2000 Martin Mares <mj@suse.cz>
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -193,6 +194,101 @@
 		return err;
 	pci_set_power_state(dev, 0);
 	return 0;
+}
+
+/*
+ *  Registration of PCI drivers and handling of hot-pluggable devices.
+ */
+
+static LIST_HEAD(pci_drivers);
+
+void
+pci_register_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+
+	list_add_tail(&drv->node, &pci_drivers);
+	pci_for_each_dev(dev) {
+		if (!pci_dev_driver(dev) && drv->probe(dev))
+			dev->driver = drv;
+	}
+}
+
+void
+pci_unregister_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+
+	list_del(&drv->node);
+	pci_for_each_dev(dev) {
+		if (dev->driver == drv) {
+			if (drv->remove)
+				drv->remove(dev);
+			dev->driver = NULL;
+		}
+	}
+}
+
+void
+pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
+{
+	struct list_head *ln;
+
+	list_add_tail(&dev->bus_list, &bus->devices);
+	list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+	pci_proc_attach_device(dev);
+#endif
+	for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
+		struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
+		if (drv->probe(dev)) {
+			dev->driver = drv;
+			break;
+		}
+	}
+}
+
+static void pci_free_resources(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *res = dev->resource + i;
+		if (res->parent)
+			release_resource(res);
+	}
+}
+
+void
+pci_remove_device(struct pci_dev *dev)
+{
+	if (dev->driver->remove)
+		dev->driver->remove(dev);
+	dev->driver = NULL;
+	list_del(&dev->bus_list);
+	list_del(&dev->global_list);
+	pci_free_resources(dev);
+#ifdef CONFIG_PROC_FS
+	pci_proc_detach_device(dev);
+#endif
+}
+
+static struct pci_driver pci_compat_driver = {
+	name: "compat"
+};
+
+struct pci_driver *
+pci_dev_driver(struct pci_dev *dev)
+{
+	if (dev->driver)
+		return dev->driver;
+	else {
+		int i;
+		for(i=0; i<=PCI_ROM_RESOURCE; i++)
+			if (dev->resource[i].flags & IORESOURCE_BUSY)
+				return &pci_compat_driver;
+	}
+	return NULL;
 }
 
 
diff -u --recursive --new-file v2.3.38/linux/drivers/pci/pcisyms.c linux/drivers/pci/pcisyms.c
--- v2.3.38/linux/drivers/pci/pcisyms.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/pci/pcisyms.c	Sat Jan  8 21:36:48 2000
@@ -6,7 +6,6 @@
  *	Copyright 1998 Martin Mares
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
@@ -28,10 +27,10 @@
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_setup_device);
-#ifdef	CONFIG_PROC_FS
-EXPORT_SYMBOL(pci_proc_attach_device);
-EXPORT_SYMBOL(pci_proc_detach_device);
-#endif
+EXPORT_SYMBOL(pci_insert_device);
+EXPORT_SYMBOL(pci_remove_device);
+EXPORT_SYMBOL(pci_register_driver);
+EXPORT_SYMBOL(pci_unregister_driver);
 
 /* Obsolete functions */
 
diff -u --recursive --new-file v2.3.38/linux/drivers/pci/proc.c linux/drivers/pci/proc.c
--- v2.3.38/linux/drivers/pci/proc.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/pci/proc.c	Sat Jan  8 12:43:56 2000
@@ -224,6 +224,7 @@
 
 	cnt = 0;
 	pci_for_each_dev(dev) {
+		struct pci_driver *drv = pci_dev_driver(dev);
 		len = sprintf(buf, "%02x%02x\t%04x%04x\t%x",
 			dev->bus->number,
 			dev->devfn,
@@ -237,6 +238,9 @@
 		for(i=0; i<7; i++)
 			len += sprintf(buf+len, LONG_FORMAT, dev->resource[i].start < dev->resource[i].end ?
 				       dev->resource[i].end - dev->resource[i].start + 1 : 0);
+		buf[len++] = '\t';
+		if (drv)
+			len += sprintf(buf+len, "%s", drv->name);
 		buf[len++] = '\n';
 		at += len;
 		if (at >= pos) {
diff -u --recursive --new-file v2.3.38/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- v2.3.38/linux/drivers/pcmcia/cardbus.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/pcmcia/cardbus.c	Sun Jan  9 16:36:02 2000
@@ -99,11 +99,6 @@
 #define PCDATA_CODE_TYPE	0x0014
 #define PCDATA_INDICATOR	0x0015
 
-#ifndef CONFIG_PROC_FS
-#define pci_proc_attach_device(dev)	do { } while (0)
-#define pci_proc_detach_device(dev)	do { } while (0)
-#endif
-
 typedef struct cb_config_t {
 	struct pci_dev dev;
 } cb_config_t;
@@ -261,6 +256,21 @@
     
 =====================================================================*/
 
+static int cb_assign_irq(u32 mask)
+{
+	int irq, try;
+
+	for (try = 0; try < 2; try++) {
+		for (irq = 1; irq < 32; irq++) {
+			if ((mask >> irq) & 1) {
+				if (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0)
+					return irq;
+			}
+		}
+	}
+	return 0;
+}
+
 int cb_alloc(socket_info_t * s)
 {
 	struct pci_bus *bus;
@@ -268,6 +278,7 @@
 	u_short vend, v, dev;
 	u_char i, hdr, fn;
 	cb_config_t *c;
+	int irq;
 
 	bus = s->cap.cb_dev->subordinate;
 	memset(&tmp, 0, sizeof(tmp));
@@ -297,8 +308,10 @@
 		return CS_OUT_OF_RESOURCE;
 	memset(c, 0, fn * sizeof(struct cb_config_t));
 
+	irq = s->cap.pci_irq;
 	for (i = 0; i < fn; i++) {
 		struct pci_dev *dev = &c[i].dev;
+		u8 irq_pin;
 		int r;
 
 		dev->bus = bus;
@@ -306,9 +319,10 @@
 		dev->devfn = i;
 		dev->vendor = vend;
 		pci_readw(dev, PCI_DEVICE_ID, &dev->device);
-		dev->hdr_type = hdr;
+		dev->hdr_type = hdr & 0x7f;
 
 		pci_setup_device(dev);
+
 		/* FIXME: Do we need to enable the expansion ROM? */
 		for (r = 0; r < 7; r++) {
 			struct resource *res = dev->resource + r;
@@ -319,28 +333,25 @@
 				pci_assign_resource(dev, r);
 			}
 		}
-
-		list_add_tail(&dev->bus_list, &bus->devices);
-		list_add_tail(&dev->global_list, &pci_devices);
-		pci_proc_attach_device(dev);
 		pci_enable_device(dev);
+
+		/* Does this function have an interrupt at all? */
+		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
+		if (irq_pin) {
+			if (!irq)
+				irq = cb_assign_irq(s->cap.irq_mask);
+			dev->irq = irq;
+			pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
+		}
+
+		pci_insert_device(dev, bus);
 	}
 
 	s->cb_config = c;
+	s->irq.AssignedIRQ = irq;
 	return CS_SUCCESS;
 }
 
-static void free_resources(struct pci_dev *dev)
-{
-	int i;
-
-	for (i = 0; i < 7; i++) {
-		struct resource *res = dev->resource + i;
-		if (res->parent)
-			release_resource(res);
-	}
-}
-
 void cb_free(socket_info_t * s)
 {
 	cb_config_t *c = s->cb_config;
@@ -349,14 +360,9 @@
 		int i;
 
 		s->cb_config = NULL;
-		for(i=0; i<s->functions; i++) {
-			struct pci_dev *dev = &c[i].dev;
+		for (i = 0 ; i < s->functions ; i++)
+			pci_remove_device(&c[i].dev);
 
-			list_del(&dev->bus_list);
-			list_del(&dev->global_list);
-			free_resources(dev);
-			pci_proc_detach_device(dev);
-		}
 		kfree(c);
 		printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number);
 	}
@@ -374,54 +380,8 @@
     
 ======================================================================*/
 
-static int cb_assign_irq(u32 mask)
-{
-	int irq, try;
-
-	for (try = 0; try < 2; try++) {
-		for (irq = 1; irq < 32; irq++) {
-			if ((mask >> irq) & 1) {
-				if (try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0)
-					return irq;
-			}
-		}
-	}
-	return 0;
-}
-
 int cb_config(socket_info_t * s)
 {
-	cb_config_t *c = s->cb_config;
-	u_char fn = s->functions;
-	int i, irq;
-
-	printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cb_dev->subordinate->number);
-
-	/*
-	 * If we have a PCI interrupt for the bridge,
-	 * then use that..
-	 */
-	irq = s->cap.pci_irq;
-
-	for (i = 0; i < fn; i++) {
-		struct pci_dev *dev = &c[i].dev;
-		u8 irq_pin;
-
-		/* Does this function have an interrupt at all? */
-		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
-		if (!irq_pin)
-			continue;
-
-		if (!irq) {
-			irq = cb_assign_irq(s->cap.irq_mask);
-			if (!irq)
-				return CS_OUT_OF_RESOURCE;
-		}
-
-		dev->irq = irq;
-		pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
-	}
-	s->irq.AssignedIRQ = irq;
 	return CS_SUCCESS;
 }
 
diff -u --recursive --new-file v2.3.38/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.3.38/linux/drivers/pcmcia/cs.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/pcmcia/cs.c	Mon Jan 10 16:13:09 2000
@@ -1143,6 +1143,29 @@
     return pcmcia_get_window(win, (*win)->index+1, req);
 }
 
+/*=====================================================================
+
+    Return the PCI device associated with a card..
+
+======================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+struct pci_bus *pcmcia_lookup_bus(client_handle_t handle)
+{
+	socket_info_t *s;
+
+	if (CHECK_HANDLE(handle))
+		return NULL;
+	s = SOCKET(handle);
+	if (!(s->state & SOCKET_CARDBUS))
+		return NULL;
+
+	return s->cap.cb_dev->subordinate;
+}
+
+#endif
+
 /*======================================================================
 
     Get the current socket state bits.  We don't support the latched
diff -u --recursive --new-file v2.3.38/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- v2.3.38/linux/drivers/pcmcia/ds.c	Tue Dec 14 01:27:24 1999
+++ linux/drivers/pcmcia/ds.c	Mon Jan 10 16:13:09 2000
@@ -46,6 +46,7 @@
 #include <linux/ioctl.h>
 #include <linux/proc_fs.h>
 #include <linux/poll.h>
+#include <linux/pci.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -429,15 +430,55 @@
     socket_info_t *s = &socket_table[i];
     socket_bind_t *b;
     dev_node_t *node;
-    
+
+#ifdef CONFIG_CARDBUS
+    /*
+     * Some unbelievably ugly code to associate the PCI cardbus
+     * device and its driver with the PCMCIA "bind" information.
+     */
+    {
+	struct pci_bus *bus;
+
+	bus = pcmcia_lookup_bus(s->handle);
+	if (bus) {
+	    	struct list_head *list;
+		struct pci_dev *dev = NULL;
+		
+		list = bus->devices.next;
+		while (list != &bus->devices) {
+			struct pci_dev *pdev = pci_dev_b(list);
+			list = list->next;
+
+			if (first) {
+				dev = pdev;
+				break;
+			}
+
+			/* Try to handle "next" here some way? */
+		}
+		if (dev && dev->driver) {
+			strncpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
+			bind_info->name[DEV_NAME_LEN-1] = '\0';
+			bind_info->major = 0;
+			bind_info->minor = 0;
+			bind_info->next = NULL;
+			return 0;
+		}
+	}
+    }
+#endif
+
     for (b = s->bind; b; b = b->next)
 	if (strcmp((char *)b->driver->dev_info,
 		   (char *)bind_info->dev_info) == 0)
 	    break;
     if (b == NULL) return -ENODEV;
-    if ((b->instance == NULL) ||
-	(b->instance->state & DEV_CONFIG_PENDING))
+
+    if (b->instance == NULL)
 	return -EAGAIN;
+    if (b->instance->state & DEV_CONFIG_PENDING)
+	return -EAGAIN;
+
     if (first)
 	node = b->instance->dev;
     else
diff -u --recursive --new-file v2.3.38/linux/drivers/pcmcia/pci_socket.c linux/drivers/pcmcia/pci_socket.c
--- v2.3.38/linux/drivers/pcmcia/pci_socket.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/pcmcia/pci_socket.c	Mon Jan 10 16:13:09 2000
@@ -166,8 +166,10 @@
 {
 	pci_socket_t *socket = nr + pci_socket_array;
 
+	memset(socket, 0, sizeof(*socket));
 	socket->dev = dev;
 	socket->op = ops;
+	init_waitqueue_head(&socket->wait);
 	return socket->op->open(socket);
 }
 
diff -u --recursive --new-file v2.3.38/linux/drivers/pcmcia/pci_socket.h linux/drivers/pcmcia/pci_socket.h
--- v2.3.38/linux/drivers/pcmcia/pci_socket.h	Tue Jan  4 13:57:17 2000
+++ linux/drivers/pcmcia/pci_socket.h	Mon Jan 10 16:13:09 2000
@@ -14,7 +14,8 @@
 	void *info;
 	struct pci_socket_ops *op;
 	socket_cap_t cap;
-	struct timer_list timer;
+	wait_queue_head_t wait;
+	unsigned int events;
 } pci_socket_t;
 
 struct pci_socket_ops {
diff -u --recursive --new-file v2.3.38/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.3.38/linux/drivers/pcmcia/yenta.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/pcmcia/yenta.c	Mon Jan 10 16:42:56 2000
@@ -385,13 +385,12 @@
 	/* Not done yet */
 }
 
-static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static unsigned int yenta_events(pci_socket_t *socket)
 {
 	u8 csc;
 	u32 cb_event;
 	unsigned int events;
-	pci_socket_t *socket = (pci_socket_t *) dev_id;
-
+	
 	/* Clear interrupt status for the event */
 	cb_event = cb_readl(socket, CB_SOCKET_EVENT);
 	cb_writel(socket, CB_SOCKET_EVENT, cb_event);
@@ -407,16 +406,50 @@
 		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
 		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
 	}
+	return events;
+}
 
-	if (events && socket->handler)
-		socket->handler(socket->info, events);
+static void yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned int events;
+	pci_socket_t *socket = (pci_socket_t *) dev_id;
 
-	mod_timer(&socket->timer, jiffies + HZ);
+	events = yenta_events(socket);
+	if (events) {
+		socket->events |= events;
+		wake_up_interruptible(&socket->wait);
+	}
 }
 
-static void yenta_timer(unsigned long data)
+/*
+ * Watch a socket every second (and possibly in a
+ * more timely manner if the state change interrupt
+ * works..)
+ */
+static int socket_thread(void * data)
 {
-	yenta_interrupt(0, (pci_socket_t *) data, NULL);
+	pci_socket_t * socket = (pci_socket_t *) data;
+	DECLARE_WAITQUEUE(wait, current);
+
+	daemonize();
+	strcpy(current->comm, "CardBus Watcher");
+
+	do {
+		unsigned int events = socket->events | yenta_events(socket);
+
+		if (events) {
+			socket->events = 0;
+			if (socket->handler)
+				socket->handler(socket->info, events);
+		}
+
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&socket->wait, &wait);
+		if (!socket->events)
+			schedule_timeout(HZ);
+		remove_wait_queue(&socket->wait, &wait);
+	} while (!signal_pending(current));
+	return 0;
 }
 
 static unsigned int yenta_probe_irq(pci_socket_t *socket)
@@ -645,22 +678,13 @@
 	/* Set up the bridge regions.. */
 	yenta_allocate_resources(socket);
 
-	/*
-	 * Always poll the socket too, just in case the cardbus interrupt
-	 * doesn't exist (it happens), or we just lose an interrupt..
-	 */
-	init_timer(&socket->timer);
-	socket->timer.expires = jiffies + HZ;
-	socket->timer.data = (unsigned long)socket;
-	socket->timer.function = yenta_timer;
-	add_timer(&socket->timer);
-
 	if (dev->irq && !request_irq(dev->irq, yenta_interrupt, SA_SHIRQ, dev->name, socket))
 		socket->cb_irq = dev->irq;
 
 	/* And figure out what the dang thing can do for the PCMCIA layer... */
 	yenta_get_socket_capabilities(socket);
 
+	kernel_thread(socket_thread, socket, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	printk("Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
 	return 0;
 }
diff -u --recursive --new-file v2.3.38/linux/drivers/pnp/Makefile linux/drivers/pnp/Makefile
--- v2.3.38/linux/drivers/pnp/Makefile	Fri Jan  7 19:13:22 2000
+++ linux/drivers/pnp/Makefile	Sat Jan  8 12:38:19 2000
@@ -12,18 +12,16 @@
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS)
 
-L_TARGET := pnp.a
-MX_OBJS  :=
-LX_OBJS  := 
-MI_OBJS  :=
-MIX_OBJS :=
+ifeq ($(CONFIG_ISAPNP),m)
+M_OBJS   := isa-pnp.o
+endif
 
-ifeq ($(CONFIG_ISAPNP),y)
-  LX_OBJS += isapnp.o quirks.o
-else
-  ifeq ($(CONFIG_ISAPNP),m)
-    MX_OBJS += isapnp.o quirks.o
-  endif
+O_TARGET := isa-pnp.o
+OX_OBJS  := isapnp.o
+O_OBJS   := quirks.o
+
+ifdef CONFIG_PROC_FS
+O_OBJS   += isapnp_proc.o
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.38/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.3.38/linux/drivers/pnp/isapnp.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/pnp/isapnp.c	Mon Jan 10 14:05:33 2000
@@ -30,31 +30,17 @@
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
-#include <linux/proc_fs.h>
 #include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/poll.h>
 #include <linux/init.h>
-#include <asm/uaccess.h>
 #include <linux/isapnp.h>
 
 LIST_HEAD(isapnp_cards);
 LIST_HEAD(isapnp_devices);
 
-#define isapnp_for_each_card(card) \
-	for(card = pci_bus_b(isapnp_cards.next); card != pci_bus_b(&isapnp_cards); card = pci_bus_b(card->node.next))
-#define isapnp_for_each_dev(dev) \
-	for(dev = pci_dev_g(isapnp_devices.next); dev != pci_dev_g(&isapnp_devices); dev = pci_dev_g(dev->global_list.next))
-
-
-#ifdef CONFIG_PROC_FS
-#include "isapnp_proc.c"
-#endif
-
 #if 0
 #define ISAPNP_REGION_OK
 #endif
@@ -286,6 +272,12 @@
 			return 0;
 		}
 		rdp += RDP_STEP;
+		/*
+		 *	We cannot use NE2000 probe spaces for ISAPnP or we
+		 *	will lock up machines.
+		 */
+		if(rdp >= 0x280 && rdp <= 0x380)
+			continue;
 	}
 	return -1;
 }
@@ -298,12 +290,8 @@
 }
 
 /*
- *	This code is badly broken. We cannot simply pick ports as the 
- *	ISAPnP specification implies. We should try 4 or 5 safe ports
- *	then bale by default.
- *
- *	This code touches NE2K cards or other devices and your box is
- *	history.
+ *	Perform an isolation. The port selection code now tries to avoid
+ *	"dangerous to read" ports.
  */
 
 static int __init isapnp_isolate_rdp_select(void)
@@ -996,6 +984,7 @@
 		card->device = (header[3] << 8) | header[2];
 		card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
 		isapnp_checksum_value = 0x00;
+		INIT_LIST_HEAD(&card->devices);
 		isapnp_parse_resource_map(card);
 		if (isapnp_checksum_value != 0x00)
 			printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
@@ -1633,7 +1622,10 @@
 	int i;
 	struct pci_dev *dev;
 
-	if (dma < 0 || dma == 4 || dma > 7)
+	/* Some machines allow DMA 0, but others don't. In fact on some 
+	   boxes DMA 0 is the memory refresh. Play safe */
+	   
+	if (dma < 1 || dma == 4 || dma > 7)
 		return 1;
 	for (i = 0; i < 8; i++) {
 		if (isapnp_reserve_dma[i] == dma)
diff -u --recursive --new-file v2.3.38/linux/drivers/pnp/isapnp_proc.c linux/drivers/pnp/isapnp_proc.c
--- v2.3.38/linux/drivers/pnp/isapnp_proc.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/pnp/isapnp_proc.c	Sat Jan  8 12:38:19 2000
@@ -19,6 +19,17 @@
  *
  */
 
+#define __NO_VERSION__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+#include <linux/isapnp.h>
+
 struct isapnp_info_buffer {
 	char *buffer;		/* pointer to begin of buffer */
 	char *curr;		/* current position in buffer */
@@ -208,7 +219,7 @@
 	&isapnp_info_entry_operations,	/* default sound info directory file-ops */
 };
 
-static int __init isapnp_proc_init(void)
+int __init isapnp_proc_init(void)
 {
 	struct proc_dir_entry *p;
 
@@ -222,7 +233,7 @@
 }
 
 #ifdef MODULE
-static int isapnp_proc_done(void)
+int isapnp_proc_done(void)
 {
 	if (isapnp_proc_entry)
 		remove_proc_entry("isapnp",&proc_root);
@@ -533,10 +544,9 @@
  
 static void isapnp_info_read(isapnp_info_buffer_t *buffer)
 {
-	struct list_head *card_list;
-	
-	for (card_list = isapnp_cards.next; card_list != &isapnp_cards; card_list = card_list->next) {
-		struct pci_bus *card = list_entry(card_list, struct pci_bus, node);
+	struct pci_bus *card;
+
+	isapnp_for_each_card(card) {
 		struct list_head *dev_list;
 
 		isapnp_printf(buffer, "Card %i '", card->number);
@@ -547,10 +557,8 @@
 		if (card->productver)
 			isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
 		isapnp_printf(buffer,"\n");
-		for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next) {
-			struct pci_dev *dev = list_entry(dev_list, struct pci_dev, bus_list);
-			isapnp_print_device(buffer, dev);
-		}
+		for (dev_list = card->devices.next; dev_list != &card->devices; dev_list = dev_list->next)
+			isapnp_print_device(buffer, pci_dev_b(dev_list));
 	}
 }
 
@@ -644,12 +652,13 @@
 	isapnp_info_device = NULL;
 	isapnp_get_str(index, line, sizeof(index));
 	csn = simple_strtoul(index, NULL, 0);
+
 	for (list = isapnp_cards.next; list != &isapnp_cards; list = list->next) {
-		isapnp_info_card = list_entry(list, struct pci_bus, node);
+		isapnp_info_card = pci_bus_b(list);
 		if (isapnp_info_card->number == csn)
 			break;
 	}
-	if (isapnp_info_card == NULL) {
+	if (list == &isapnp_cards) {
 		printk("isapnp: cannot find CSN %i\n", csn);
 		return 1;
 	}
diff -u --recursive --new-file v2.3.38/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.3.38/linux/drivers/sbus/char/pcikbd.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/sbus/char/pcikbd.c	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.40 1999/12/01 10:45:53 davem Exp $
+/* $Id: pcikbd.c,v 1.41 2000/01/08 07:01:20 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx
--- v2.3.38/linux/drivers/scsi/ChangeLog.ncr53c8xx	Mon Dec 20 18:48:21 1999
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Sat Jan  8 12:50:16 2000
@@ -1,3 +1,9 @@
+Sat Jan 8  22:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2e
+	- Add year 2000 copyright.
+	- Display correctly bus signals when bus is detected wrong.
+	- Remove the dead code that broke driver 3.2d.
+
 Mon Dec 6  22:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.2d
 	- Change messages written by the driver at initialisation and 
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/ChangeLog.sym53c8xx linux/drivers/scsi/ChangeLog.sym53c8xx
--- v2.3.38/linux/drivers/scsi/ChangeLog.sym53c8xx	Mon Dec 20 18:48:21 1999
+++ linux/drivers/scsi/ChangeLog.sym53c8xx	Sat Jan  8 12:50:16 2000
@@ -1,3 +1,9 @@
+Sat Jan 8  22:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5h
+	- Add year 2000 copyright.
+	- Display correctly bus signals when bus is detected wrong.
+	- Some fix for Sparc from DSM that went directly to kernel tree.
+
 Mon Dec 6  22:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* version sym53c8xx-1.5g
 	- Change messages written by the driver at initialisation and 
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.3.38/linux/drivers/scsi/ncr53c8xx.c	Mon Dec 20 18:48:22 1999
+++ linux/drivers/scsi/ncr53c8xx.c	Sat Jan  8 12:50:16 2000
@@ -73,7 +73,7 @@
 */
 
 /*
-**	December 6 1999, version 3.2d
+**	January 8 2000, version 3.2e
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -104,7 +104,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2d"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2e"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -5400,11 +5400,13 @@
 	**	We are expecting RESET to be TRUE and other signals to be 
 	**	FALSE.
 	*/
-	term =	INB(nc_sstat0);				/* rst, sdp0 */
-	term =	((term & 2) << 7) + ((term & 1) << 16);
-	term |= ((INB(nc_sstat2) & 0x01) << 25) |	/* sdp1 */
-		(INW(nc_sbdl) << 9) |			/* d15-0 */
-		INB(nc_sbcl);	/* req, ack, bsy, sel, atn, msg, cd, io */
+
+	term =	INB(nc_sstat0);
+	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
+	term |= ((INB(nc_sstat2) & 0x01) << 26) |	/* sdp1     */
+		((INW(nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
+		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
+		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
 
 	if (!(np->features & FE_WIDE))
 		term &= 0x3ffff;
@@ -9660,9 +9662,6 @@
 	uint irq;
 	ulong base, base_2, io_port; 
 	int i;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	ncr_nvram *nvram = device->nvram;
-#endif
 	ncr_chip *chip;
 
 	/*
@@ -10001,52 +10000,7 @@
 	device->slot.io_port	= io_port;
 	device->slot.irq	= irq;
 	device->attach_done	= 0;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	if (!nvram)
-		goto out;
 
-	/*
-	** Get access to chip IO registers
-	*/
-#ifdef NCR_IOMAPPED
-	request_region(io_port, 128, "ncr53c8xx");
-	device->slot.port = io_port;
-#else
-	device->slot.reg = (struct ncr_reg *) remap_pci_mem((ulong) base, 128);
-	if (!device->slot.reg)
-		goto out;
-#endif
-
-	/*
-	** Try to read SYMBIOS nvram.
-	** Data can be used to order booting of boards.
-	**
-	** Data is saved in ncr_device structure if NVRAM found. This
-	** is then used to find drive boot order for ncr_attach().
-	**
-	** NVRAM data is passed to Scsi_Host_Template later during ncr_attach()
-	** for any device set up.
-	**
-	** Try to read TEKRAM nvram if Symbios nvram not found.
-	*/
-
-	if	(!ncr_get_Symbios_nvram(&device->slot, &nvram->data.Symbios))
-		nvram->type = SCSI_NCR_SYMBIOS_NVRAM;
-	else if	(!ncr_get_Tekram_nvram(&device->slot, &nvram->data.Tekram))
-		nvram->type = SCSI_NCR_TEKRAM_NVRAM;
-	else
-		nvram->type = 0;
-out:
-	/*
-	** Release access to chip IO registers
-	*/
-#ifdef NCR_IOMAPPED
-	release_region(device->slot.port, 128);
-#else
-	unmap_pci_mem((vm_offset_t) device->slot.reg, (u_long) 128);
-#endif
-
-#endif	/* SCSI_NCR_NVRAM_SUPPORT */
 	return 0;     
 }
 
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.3.38/linux/drivers/scsi/qlogicisp.c	Wed Dec 29 13:13:18 1999
+++ linux/drivers/scsi/qlogicisp.c	Sat Jan  8 12:52:54 2000
@@ -2,7 +2,9 @@
  * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
  * Written by Erik H. Moe, ehm@cris.com
  * Copyright 1995, Erik H. Moe
- * Copyright 1996, 1997  Michael A. Griffith <grif@acm.org> 
+ * Copyright 1996, 1997  Michael A. Griffith <grif@acm.org>
+ * Copyright 2000, Jayson C. Vantuyl <vantuyl@csc.smsu.edu>
+ *             and Bryon W. Roche    <bryon@csc.smsu.edu>
  *
  * 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
@@ -555,6 +557,10 @@
 static void	isp1020_print_status_entry(struct Status_Entry *);
 #endif
 
+/* memaddr should be used to determine if memmapped port i/o is being used
+ * non-null memaddr == mmap'd
+ * JV 7-Jan-2000
+ */
 static inline u_short isp_inw(struct Scsi_Host *host, long offset)
 {
 	struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
@@ -607,15 +613,23 @@
 		hostdata = (struct isp1020_hostdata *) host->hostdata;
 
 		memset(hostdata, 0, sizeof(struct isp1020_hostdata));
+
 		hostdata->pci_dev = pdev;
 
-		if (isp1020_init(host) || isp1020_reset_hardware(host)
+		if (isp1020_init(host)) {
+			scsi_unregister(host);
+			continue;
+		}
+		
+		if (isp1020_reset_hardware(host)
 #if USE_NVRAM_DEFAULTS
 		    || isp1020_get_defaults(host)
 #else
 		    || isp1020_set_defaults(host)
 #endif /* USE_NVRAM_DEFAULTS */
 		    || isp1020_load_parameters(host)) {
+			iounmap((void *)hostdata->memaddr);
+			release_region(host->io_port, 0xff);
 			scsi_unregister(host);
 			continue;
 		}
@@ -627,21 +641,12 @@
 		{
 			printk("qlogicisp : interrupt %d already in use\n",
 			       host->irq);
+			iounmap((void *)hostdata->memaddr);
+			release_region(host->io_port, 0xff);
 			scsi_unregister(host);
 			continue;
 		}
 
-		if (check_region(host->io_port, 0xff)) {
-			printk("qlogicisp : i/o region 0x%lx-0x%lx already "
-			       "in use\n",
-			       host->io_port, host->io_port + 0xff);
-			free_irq(host->irq, host);
-			scsi_unregister(host);
-			continue;
-		}
-
-		request_region(host->io_port, 0xff, "qlogicisp");
-
 		isp_outw(0x0, host, PCI_SEMAPHORE);
 		isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
 		isp1020_enable_irqs(host);
@@ -666,6 +671,8 @@
 	isp_outw(0x0, host, PCI_INTF_CTL);
 	free_irq(host->irq, host);
 
+	iounmap((void *)hostdata->memaddr);
+
 	release_region(host->io_port, 0xff);
 
 	LEAVE("isp1020_release");
@@ -685,8 +692,8 @@
 	sprintf(buf,
 		"QLogic ISP1020 SCSI on PCI bus %02x device %02x irq %d %s base 0x%lx",
 		hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq,
-		(host->io_port ? "I/O" : "MEM"),
-		(host->io_port ? host->io_port : hostdata->memaddr));
+		(hostdata->memaddr ? "MEM" : "I/O"),
+		(hostdata->memaddr ? hostdata->memaddr : host->io_port));
 
 	LEAVE("isp1020_info");
 
@@ -1255,27 +1262,37 @@
 	command &= ~PCI_COMMAND_MEMORY; 
 #endif
 
+	if (!(command & PCI_COMMAND_MASTER)) {
+		printk("qlogicisp : bus mastering is disabled\n");
+		return 1;
+	}
+
+	sh->io_port = io_base;
+
+	if (check_region(sh->io_port, 0xff)) {
+		printk("qlogicisp : i/o region 0x%lx-0x%lx already "
+		       "in use\n",
+		       sh->io_port, sh->io_port + 0xff);
+		return 1;
+	}
+
+	request_region(sh->io_port, 0xff, "qlogicisp");
+
  	if ((command & PCI_COMMAND_MEMORY) &&
  	    ((mem_flags & 1) == 0)) {
  		mem_base = (u_long) ioremap(mem_base, PAGE_SIZE);
  		hostdata->memaddr = mem_base;
- 		io_base = 0;
  	} else {
  		if (command & PCI_COMMAND_IO && (io_flags & 3) != 1)
  		{
  			printk("qlogicisp : i/o mapping is disabled\n");
+			release_region(sh->io_port, 0xff);
  			return 1;
  		}
- 		hostdata->memaddr = 0;
- 		sh->io_port = io_base;
+ 		hostdata->memaddr = 0; /* zero to signify no i/o mapping */
  		mem_base = 0;
 	}
 
-	if (!(command & PCI_COMMAND_MASTER)) {
-		printk("qlogicisp : bus mastering is disabled\n");
-		return 1;
-	}
-
 	if (revision != ISP1020_REV_ID)
 		printk("qlogicisp : new isp1020 revision ID (%d)\n", revision);
 
@@ -1285,6 +1302,8 @@
 		printk("qlogicisp : can't decode %s address space 0x%lx\n",
 		       (io_base ? "I/O" : "MEM"),
 		       (io_base ? io_base : mem_base));
+		iounmap((void *)hostdata->memaddr);
+		release_region(sh->io_port, 0xff);
 		return 1;
 	}
 
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- v2.3.38/linux/drivers/scsi/scsi_merge.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/scsi/scsi_merge.c	Sat Jan  8 12:57:44 2000
@@ -790,7 +790,9 @@
 	 */
 	if (count != SCpnt->use_sg) {
 		printk("Incorrect number of segments after building list\n");
+#ifdef CONFIG_SCSI_DEBUG_QUEUES
 		dump_stats(req, use_clustering, dma_host, count);
+#endif
 	}
 	if (!dma_host) {
 		return 1;
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.38/linux/drivers/scsi/sd.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/scsi/sd.c	Sat Jan  8 21:36:48 2000
@@ -19,6 +19,7 @@
  *       scsi disks using eight major numbers.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #ifdef MODULE
 /*
@@ -452,7 +453,6 @@
 static int sd_release(struct inode *inode, struct file *file)
 {
 	int target;
-	fsync_dev(inode->i_rdev);
 
 	target = DEVICE_NR(inode->i_rdev);
 
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.3.38/linux/drivers/scsi/sym53c8xx.c	Wed Dec 29 13:13:19 1999
+++ linux/drivers/scsi/sym53c8xx.c	Sat Jan  8 12:50:16 2000
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-2000  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -55,7 +55,7 @@
 */
 
 /*
-**	December 6 1999, sym53c8xx 1.5g
+**	January 9 2000, sym53c8xx 1.5h
 **
 **	Supported SCSI features:
 **	    Synchronous data transfers
@@ -84,7 +84,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5g"
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5h"
 
 /* #define DEBUG_896R1 */
 #define SCSI_NCR_OPTIMIZE_896
@@ -6367,11 +6367,12 @@
 	**	We are expecting RESET to be TRUE and other signals to be 
 	**	FALSE.
 	*/
-	term =	INB(nc_sstat0);				/* rst, sdp0 */
-	term =	((term & 2) << 7) + ((term & 1) << 16);
-	term |= ((INB(nc_sstat2) & 0x01) << 25) |	/* sdp1 */
-		(INW(nc_sbdl) << 9) |			/* d15-0 */
-		INB(nc_sbcl);	/* req, ack, bsy, sel, atn, msg, cd, io */
+	term =	INB(nc_sstat0);
+	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
+	term |= ((INB(nc_sstat2) & 0x01) << 26) |	/* sdp1     */
+		((INW(nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
+		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
+		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
 
 	if (!(np->features & FE_WIDE))
 		term &= 0x3ffff;
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h
--- v2.3.38/linux/drivers/scsi/sym53c8xx.h	Sat Oct  9 11:47:50 1999
+++ linux/drivers/scsi/sym53c8xx.h	Mon Jan 10 18:31:34 2000
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-2000  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
diff -u --recursive --new-file v2.3.38/linux/drivers/scsi/sym53c8xx_defs.h linux/drivers/scsi/sym53c8xx_defs.h
--- v2.3.38/linux/drivers/scsi/sym53c8xx_defs.h	Mon Dec 20 18:48:22 1999
+++ linux/drivers/scsi/sym53c8xx_defs.h	Mon Jan 10 18:31:04 2000
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-2000  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
diff -u --recursive --new-file v2.3.38/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.3.38/linux/drivers/sound/trident.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/sound/trident.c	Mon Jan 10 14:05:33 2000
@@ -29,6 +29,8 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.05 Jan 08 2000 Luca Montecchiani <m.luca@iname.com>
+ *     adapt to 2.3.x new __setup/__initcall
  *  v0.04 Dec 31 1999 Ollie Lho
  *	Multiple Open, useing Middle Loop Interrupt to smooth playback
  *  v0.03 Dec 24 1999 Ollie Lho
@@ -68,7 +70,7 @@
 
 #undef DEBUG
 
-#define DRIVER_VERSION "0.03"
+#define DRIVER_VERSION "0.05"
 
 #define TRIDENT_FMT_STEREO     0x01
 #define TRIDENT_FMT_16BIT      0x02
@@ -2921,11 +2923,7 @@
 	return 1; 
 }
 
-#ifdef MODULE
-int init_module(void)
-#else
-int __init init_trident(void)
-#endif
+static int __init init_trident(void)
 {
 	struct pci_dev *pcidev = NULL;
 	int foundone = 0;
@@ -2951,15 +2949,14 @@
 	return 0;
 }
 
-#ifdef MODULE
-MODULE_AUTHOR("Alan Cox <alan@redhat.com>");
+MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho");
 MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
 
 #ifdef DEBUG
 MODULE_PARM(debug,"i");
 #endif
 
-void cleanup_module(void)
+static void __exit cleanup_trident(void)
 {
 	while (devs != NULL) {
 		/* Kill interrupts, and SP/DIF */
@@ -2978,6 +2975,8 @@
 		devs = devs->next;
 	}
 }
-#endif /* MODULE */
+
+module_init(init_trident);
+module_exit(cleanup_trident);
 
 
diff -u --recursive --new-file v2.3.38/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c
--- v2.3.38/linux/drivers/telephony/ixj.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/telephony/ixj.c	Mon Jan 10 14:05:33 2000
@@ -1973,7 +1973,7 @@
 
 		ixj_WriteDSPCommand(0x0700, board);
 	}
-	if (ixj[board].play_mode != -1 && ixj[board].rec_mode != -1);
+	if (ixj[board].play_mode != -1 && ixj[board].rec_mode != -1)
 	{
 		ixj_WriteDSPCommand(0xB002, board);	// AEC Stop
 
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.38/linux/drivers/usb/Config.in	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/Config.in	Mon Jan 10 16:05:19 2000
@@ -8,13 +8,14 @@
 if [ ! "$CONFIG_USB" = "n" ]; then
 
 comment 'USB Controllers'
-   dep_tristate '  UHCI (Intel PIIX4, VIA, and others) support' CONFIG_USB_UHCI $CONFIG_USB
-   dep_tristate '  OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, and others) support' CONFIG_USB_OHCI_HCD $CONFIG_USB
+   dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+   dep_tristate '  OHCI-HCD (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI_HCD $CONFIG_USB
 
 comment 'Miscellaneous USB options'
    if [ "$CONFIG_PROC_FS" != "n" ]; then
       bool '  /proc/bus/usb support' CONFIG_USB_PROC
    fi
+   bool '  Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
 
 comment 'USB Devices'
    dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.38/linux/drivers/usb/Makefile	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/Makefile	Mon Jan 10 11:32:48 2000
@@ -32,6 +32,9 @@
 ifeq ($(CONFIG_USB_PROC),y)
 	usbcore-objs	+= proc_usb.o
 endif
+ifeq ($(CONFIG_USB_DEVICEFS),y)
+	usbcore-objs	+= devio.o inode.o drivers.o devices.o
+endif
 ifeq ($(CONFIG_USB_SCSI_DEBUG),y)
 	usb-scsi-objs	+= usb_scsi_debug.o
 endif
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.38/linux/drivers/usb/acm.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/acm.c	Mon Jan 10 11:38:29 2000
@@ -1,5 +1,5 @@
 /*
- * acm.c  Version 0.11
+ * acm.c  Version 0.12
  *
  * Copyright (c) 1999 Armin Fuerst	<fuerst@in.tum.de>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
@@ -15,6 +15,7 @@
  *	v0.10 - some more cleanups
  *	v0.11 - fixed flow control, read error doesn't stop reads
  *	v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
+ *	v0.13 - added termios, added hangup
  */
 
 /*
@@ -75,7 +76,7 @@
 #define ACM_REQ_SEND_BREAK	0x23
 
 /*
- * IRQs
+ * IRQs.
  */
 
 #define ACM_IRQ_NETWORK		0x00
@@ -105,7 +106,7 @@
  * Line speed and caracter encoding.
  */
 
-struct acm_coding {
+struct acm_line {
 	__u32 speed;
 	__u8 stopbits;
 	__u8 parity;
@@ -118,21 +119,21 @@
 
 struct acm {
 	struct usb_device *dev;				/* the coresponding usb device */
-	struct usb_config_descriptor *cfg;		/* configuration number on this device */
+	struct usb_interface *iface;			/* the interfaces - +0 control +1 data */
 	struct tty_struct *tty;				/* the coresponding tty */
-	unsigned int ctrlif;				/* interface number for acm control messages */
 	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */
 	unsigned int ctrlout;				/* output control lines (DTR, RTS) */
-	struct acm_coding linecoding;			/* line coding (bits, stop, parity) */
+	struct acm_line line;				/* line coding (bits, stop, parity) */
 	unsigned int writesize;				/* max packet size for the output bulk endpoint */
 	struct urb ctrlurb, readurb, writeurb;		/* urbs */
 	unsigned int minor;				/* acm minor number */
 	unsigned int present;				/* this device is connected to the usb bus */
 	unsigned int used;				/* someone has this acm's device open */
+	unsigned int clocal;				/* termios CLOCAL */
 };
 
 static struct usb_driver acm_driver;
-static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, NULL, NULL, /* .... */ };
+static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, /* .... */ };
 
 #define ACM_READY(acm)	(acm && acm->present && acm->used)
 
@@ -143,13 +144,13 @@
 static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
 {
 	int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
-		request, USB_RT_ACM, value, acm->ctrlif, buf, len, HZ * 5);
+		request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);
 	dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
 	return retval < 0 ? retval : 0;
 }
 
-#define	acm_set_control(acm, control)	acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
-#define acm_set_coding(acm, coding) 	acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, coding, sizeof(struct acm_coding))
+#define acm_set_control(acm, control)	acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
+#define acm_set_line(acm, line)		acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))
 #define acm_send_break(acm, ms)		acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
 
 /*
@@ -161,6 +162,7 @@
 	struct acm *acm = urb->context;
 	devrequest *dr = urb->transfer_buffer;
 	unsigned char *data = (unsigned char *)(dr + 1);
+	int newctrl;
 
 	if (!ACM_READY(acm)) return;
 
@@ -178,7 +180,14 @@
 
 		case ACM_IRQ_LINE_STATE:
 
-			acm->ctrlin = data[0] | (((unsigned int) data[1]) << 8);
+			newctrl = le16_to_cpup(data);
+
+			if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
+				dbg("calling hangup");
+				tty_hangup(acm->tty);
+			}
+
+			acm->ctrlin = newctrl;
 
 			dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
 				acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',	acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
@@ -352,7 +361,7 @@
 static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct acm *acm = tty->driver_data;
-	unsigned int retval, ctrl, old;
+	unsigned int retval, mask, newctrl;
 
 	if (!ACM_READY(acm)) return -EINVAL;
 
@@ -371,26 +380,68 @@
 		case TIOCMBIS:
 		case TIOCMBIC:
 
-			if ((retval = get_user(ctrl, (unsigned long *) arg))) return retval;
+			if ((retval = get_user(mask, (unsigned long *) arg))) return retval;
 
-			ctrl = (ctrl & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (ctrl & TIOCM_RTS ? ACM_CTRL_RTS : 0);
-			old = acm->ctrlout;
+			newctrl = acm->ctrlout;
+			mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0);
 
 			switch (cmd) {
-				case TIOCMSET: acm->ctrlout  =  ctrl; break;
-				case TIOCMBIS: acm->ctrlout |=  ctrl; break;
-				case TIOCMBIC: acm->ctrlout &= ~ctrl; break;
+				case TIOCMSET: newctrl  =  mask; break;
+				case TIOCMBIS: newctrl |=  mask; break;
+				case TIOCMBIC: newctrl &= ~mask; break;
 			}
 	
-			if (acm->ctrlout == old) return 0; 
-			return acm_set_control(acm, acm->ctrlout);
+			if (acm->ctrlout == newctrl) return 0; 
+			return acm_set_control(acm, acm->ctrlout = newctrl);
 	}
 
-	dbg("unknown ioctl %#x", cmd);
-
 	return -ENOIOCTLCMD;
 }
 
+static __u32 acm_tty_speed[] = { 
+	0, 50, 75, 110, 134, 150, 200, 300, 600,
+	1200, 1800, 2400, 4800, 9600, 19200, 38400,
+	57600, 115200, 230400, 460800, 500000, 576000,
+	921600, 1000000, 1152000, 1500000, 2000000,
+	2500000, 3000000, 3500000, 4000000
+};
+
+static __u8 acm_tty_size[] = {
+	5, 6, 7, 8
+};
+
+static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
+{
+	struct acm *acm = tty->driver_data;
+	struct termios *termios = tty->termios;
+	struct acm_line newline;
+
+	if (!ACM_READY(acm)) return;
+
+	newline.speed = cpu_to_le32p(acm_tty_speed +
+		(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
+	newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
+	newline.parity = termios->c_cflag & PARENB ?
+		(termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
+	newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
+
+	acm->clocal = termios->c_cflag & CLOCAL;
+
+	if (!memcmp(&acm->line, &newline, sizeof(struct acm_line)))
+		return;
+
+	memcpy(&acm->line, &newline, sizeof(struct acm_line));
+
+	if (!newline.speed) {
+		if (acm->ctrlout) acm_set_control(acm, acm->ctrlout = 0);
+		return;
+	}
+
+	acm_set_line(acm, &acm->line);
+
+	dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);
+}
+
 /*
  * USB probe and disconnect routines.
  */
@@ -398,36 +449,21 @@
 static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct acm *acm;
+	struct usb_config_descriptor *cfacm;
 	struct usb_interface_descriptor *ifcom, *ifdata;
 	struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
 	int readsize, ctrlsize, minor, i;
 	unsigned char *buf;
 
-	for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-
-	if (acm_table[minor]) {
-		dbg("no more free acm devices");
-		return NULL;
-	}
-
-	if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) return NULL;
-	memset(acm, 0, sizeof(struct acm));
-
-	acm_table[minor] = acm;
-	acm->minor = minor;
-	acm->dev = dev;
-
 	if (dev->descriptor.bDeviceClass != 2 || dev->descriptor.bDeviceSubClass != 0
-		|| dev->descriptor.bDeviceProtocol != 0) {
-		return NULL;
-	}
+		|| dev->descriptor.bDeviceProtocol != 0) return NULL;
 
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 
-		acm->cfg = dev->config + i;
-		dbg("probing config %d", acm->cfg->bConfigurationValue);
+		cfacm = dev->config + i;
+		dbg("probing config %d", cfacm->bConfigurationValue);
 
-		ifcom = acm->cfg->interface[0].altsetting + 0;
+		ifcom = cfacm->interface[0].altsetting + 0;
 		if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
 		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
 			continue;
@@ -436,12 +472,12 @@
 		if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3)
 			continue;
 
-		ifdata = acm->cfg->interface[1].altsetting + 0;
+		ifdata = cfacm->interface[1].altsetting + 0;
 		if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
 			continue;
 
-		if (usb_interface_claimed(acm->cfg->interface + 0) ||
-		    usb_interface_claimed(acm->cfg->interface + 1))
+		if (usb_interface_claimed(cfacm->interface + 0) ||
+		    usb_interface_claimed(cfacm->interface + 1))
 			continue;
 
 		epread = ifdata->endpoint + 0;
@@ -456,13 +492,29 @@
 			epwrite = ifdata->endpoint + 0;
 		}
 
-		usb_set_configuration(dev, acm->cfg->bConfigurationValue);
+		usb_set_configuration(dev, cfacm->bConfigurationValue);
+
+		for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+		if (acm_table[minor]) {
+			dbg("no more free acm devices");
+			return NULL;
+		}
+
+		if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) return NULL;
+		memset(acm, 0, sizeof(struct acm));
 
 		ctrlsize = epctrl->wMaxPacketSize;
 		readsize = epread->wMaxPacketSize;
 		acm->writesize = epwrite->wMaxPacketSize;
+		acm->iface = cfacm->interface;
+		acm->minor = minor;
+		acm->present = 1;
+		acm->dev = dev;
 
-		if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) return NULL;
+		if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+			kfree(acm);
+			return NULL;
+		}
 
 		FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
 			buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
@@ -472,8 +524,6 @@
 
 		FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
 			buf += readsize , acm->writesize, acm_write_bulk, acm);
-
-		acm->ctrlif = ifcom->bInterfaceNumber;
 	
 		printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
 
@@ -483,12 +533,10 @@
 		acm->linecoding.databits = 8;
 		acm_set_coding(acm, &acm->linecoding);
 
-		usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 0, acm);
-		usb_driver_claim_interface(&acm_driver, acm->cfg->interface + 1, acm);
-
-		acm->present = 1;
+		usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+		usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
 
-		return acm;
+		return acm_table[minor] = acm;
 	}
 
 	return NULL;
@@ -511,13 +559,17 @@
 
 	kfree(acm->ctrlurb.transfer_buffer);
 
-	usb_driver_release_interface(&acm_driver, acm->cfg->interface + 0);
-	usb_driver_release_interface(&acm_driver, acm->cfg->interface + 1);
+	usb_driver_release_interface(&acm_driver, acm->iface + 0);
+	usb_driver_release_interface(&acm_driver, acm->iface + 1);
 
 	if (!acm->used) {
 		acm_table[acm->minor] = NULL;
 		kfree(acm);
+		return;
 	}
+
+	if (acm->tty)
+		tty_hangup(acm->tty);
 }
 
 /*
@@ -565,7 +617,8 @@
 	throttle:		acm_tty_throttle,
 	unthrottle:		acm_tty_unthrottle,
 	chars_in_buffer:	acm_tty_chars_in_buffer,
-	break_ctl:		acm_tty_break_ctl
+	break_ctl:		acm_tty_break_ctl,
+	set_termios:		acm_tty_set_termios
 };
 
 /*
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/devices.c linux/drivers/usb/devices.c
--- v2.3.38/linux/drivers/usb/devices.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/devices.c	Mon Jan 10 16:05:19 2000
@@ -0,0 +1,528 @@
+/*
+ * devices.c
+ * (C) Copyright 1999 Randy Dunlap.
+ * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
+ * (C) Copyright 1999 Deti Fliegl (new USB architecture)
+ *
+ * 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
+ *
+ *************************************************************
+ *
+ * <mountpoint>/devices contains USB topology, device, config, class,
+ * interface, & endpoint data.
+ *
+ * I considered using /proc/bus/usb/devices/device# for each device
+ * as it is attached or detached, but I didn't like this for some
+ * reason -- maybe it's just too deep of a directory structure.
+ * I also don't like looking in multiple places to gather and view
+ * the data.  Having only one file for ./devices also prevents race
+ * conditions that could arise if a program was reading device info
+ * for devices that are being removed (unplugged).  (That is, the
+ * program may find a directory for devnum_12 then try to open it,
+ * but it was just unplugged, so the directory is now deleted.
+ * But programs would just have to be prepared for situations like
+ * this in any plug-and-play environment.)
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Converted the whole proc stuff to real
+ *   read methods. Now not the whole device list needs to fit
+ *   into one page, only the device list for one bus.
+ *   Added a poll method to /proc/bus/usb/devices, to wake
+ *   up an eventual usbd
+ * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Turned into its own filesystem
+ *
+ * $Id: proc_usb.c,v 1.16 1999/12/20 11:11:10 fliegl Exp $
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+#define MAX_TOPO_LEVEL		6
+
+/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
+#define ALLOW_SERIAL_NUMBER
+
+static char *format_topo =
+/* T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
+  "T:  Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
+
+static char *format_string_manufacturer =
+/* S:  Manufacturer=xxxx */
+  "S:  Manufacturer=%s\n";
+
+static char *format_string_product =
+/* S:  Product=xxxx */
+  "S:  Product=%s\n";
+
+#ifdef ALLOW_SERIAL_NUMBER
+static char *format_string_serialnumber =
+/* S:  SerialNumber=xxxx */
+  "S:  SerialNumber=%s\n";
+#endif
+
+static char *format_bandwidth =
+/* B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
+  "B:  Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
+  
+static char *format_device1 =
+/* D:  Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
+  "D:  Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
+
+static char *format_device2 =
+/* P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx */
+  "P:  Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
+
+static char *format_config =
+/* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
+  "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
+  
+static char *format_iface =
+/* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
+  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+
+static char *format_endpt =
+/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
+  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
+
+
+/*
+ * Need access to the driver and USB bus lists.
+ * extern struct list_head usb_driver_list;
+ * extern struct list_head usb_bus_list;
+ * However, these will come from functions that return ptrs to each of them.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
+static unsigned int conndiscevcnt = 0;
+
+/* this struct stores the poll state for <mountpoint>/devices pollers */
+struct usb_device_status {
+	unsigned int lastev;
+};
+
+struct class_info {
+	int class;
+	char *class_name;
+};
+
+static const struct class_info clas_info[] =
+{					/* max. 5 chars. per name string */
+	{USB_CLASS_PER_INTERFACE,	">ifc"},
+	{USB_CLASS_AUDIO,		"audio"},
+	{USB_CLASS_COMM,		"comm."},
+	{USB_CLASS_HID,			"HID"},
+	{USB_CLASS_HUB,			"hub"},
+	{USB_CLASS_PRINTER,		"print"},
+	{USB_CLASS_MASS_STORAGE,	"stor."},
+	{USB_CLASS_DATA,		"data"},
+	{USB_CLASS_VENDOR_SPEC,		"vend."},
+	{-1,				"unk."}		/* leave as last */
+};
+
+/*****************************************************************/
+
+void usbdevfs_conn_disc_event(void)
+{
+	wake_up(&deviceconndiscwq);
+	conndiscevcnt++;
+}
+
+static const char *class_decode(const int class)
+{
+	int ix;
+
+	for (ix = 0; clas_info[ix].class != -1; ix++)
+		if (clas_info[ix].class == class)
+			break;
+	return (clas_info[ix].class_name);
+}
+
+static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
+{
+	char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
+
+	if (start > end)
+		return start;
+	start += sprintf(start, format_endpt, desc->bEndpointAddress,
+			 (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
+			 desc->bmAttributes, EndpointType[desc->bmAttributes & 3],
+			 desc->wMaxPacketSize, desc->bInterval);
+	return start;
+}
+
+static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
+{
+	return usb_dump_endpoint_descriptor(start, end, endpoint);
+}
+
+static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
+{
+	struct usb_interface_descriptor *desc = &iface->altsetting[setno];
+
+	if (start > end)
+		return start;
+	start += sprintf(start, format_iface,
+			 desc->bInterfaceNumber,
+			 desc->bAlternateSetting,
+			 desc->bNumEndpoints,
+			 desc->bInterfaceClass,
+			 class_decode(desc->bInterfaceClass),
+			 desc->bInterfaceSubClass,
+			 desc->bInterfaceProtocol,
+			 iface->driver ? iface->driver->name : "(none)");
+	return start;
+}
+
+static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
+{
+	struct usb_interface_descriptor *desc = &iface->altsetting[setno];
+	int i;
+
+	start = usb_dump_interface_descriptor(start, end, iface, setno);
+	for (i = 0; i < desc->bNumEndpoints; i++) {
+		if (start > end)
+			return start;
+		start = usb_dump_endpoint(start, end, desc->endpoint + i);
+	}
+	return start;
+}
+
+/* TBD:
+ * 0. TBDs
+ * 1. marking active config and ifaces (code lists all, but should mark
+ *    which ones are active, if any)
+ * 2. add <halted> status to each endpoint line
+ */
+
+static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, const int active)
+{
+	if (start > end)
+		return start;
+	start += sprintf(start, format_config,
+			 active ? '*' : ' ',	/* mark active/actual/current cfg. */
+			 desc->bNumInterfaces,
+			 desc->bConfigurationValue,
+			 desc->bmAttributes,
+			 desc->MaxPower * 2);
+	return start;
+}
+
+static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, const int active)
+{
+	int i, j;
+	struct usb_interface *interface;
+
+	if (start > end)
+		return start;
+	if (!config)		/* getting these some in 2.3.7; none in 2.3.6 */
+		return start + sprintf(start, "(null Cfg. desc.)\n");
+	start = usb_dump_config_descriptor(start, end, config, active);
+	for (i = 0; i < config->bNumInterfaces; i++) {
+		interface = config->interface + i;
+		if (!interface)
+			break;
+		for (j = 0; j < interface->num_altsetting; j++) {
+			if (start > end)
+				return start;
+			start = usb_dump_interface(start, end, interface, j);
+		}
+	}
+	return start;
+}
+
+/*
+ * Dump the different USB descriptors.
+ */
+static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
+{
+	if (start > end)
+		return start;
+	start += sprintf (start, format_device1,
+			  desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
+			  desc->bDeviceClass,
+			  class_decode (desc->bDeviceClass),
+			  desc->bDeviceSubClass,
+			  desc->bDeviceProtocol,
+			  desc->bMaxPacketSize0,
+			  desc->bNumConfigurations);
+	if (start > end)
+		return start;
+	start += sprintf(start, format_device2,
+			 desc->idVendor, desc->idProduct,
+			 desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
+	return start;
+}
+
+/*
+ * Dump the different strings that this device holds.
+ */
+static char *usb_dump_device_strings (char *start, char *end, const struct usb_device *dev)
+{
+	char *buf;
+
+	if (start > end)
+		return start;
+	buf = kmalloc(256, GFP_KERNEL);
+	if (!buf)
+		return start;
+
+	if (dev->descriptor.iManufacturer) {
+		if (usb_string(dev, dev->descriptor.iManufacturer, buf, 256) > 0)
+			start += sprintf(start, format_string_manufacturer, buf);
+	}				
+	if (start > end)
+		goto out;
+
+	if (dev->descriptor.iProduct) {
+		if (usb_string(dev, dev->descriptor.iProduct, buf, 256) > 0)
+			start += sprintf(start, format_string_product, buf);
+	}
+	if (start > end)
+		goto out;
+
+#ifdef ALLOW_SERIAL_NUMBER
+	if (dev->descriptor.iSerialNumber) {
+		if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 256) > 0)
+			start += sprintf(start, format_string_serialnumber, buf);
+	}
+#endif
+
+out:
+	kfree(buf);
+	return start;
+}
+
+static char *usb_dump_desc(char *start, char *end, const struct usb_device *dev)
+{
+	int i;
+
+	if (start > end)
+		return start;
+		
+	start = usb_dump_device_descriptor(start, end, &dev->descriptor);
+
+	if (start > end)
+		return start;
+	
+	start = usb_dump_device_strings (start, end, dev);
+	
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+		if (start > end)
+			return start;
+		start = usb_dump_config(start, end, dev->config + i,
+					(dev->config + i) == dev->actconfig); /* active ? */
+	}
+	return start;
+}
+
+
+#ifdef PROC_EXTRA /* TBD: may want to add this code later */
+
+static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
+{
+	int leng = USB_DT_HUB_NONVAR_SIZE;
+	unsigned char *ptr = (unsigned char *)desc;
+
+	if (start > end)
+		return start;
+	start += sprintf(start, "Interface:");
+	while (leng) {
+		start += sprintf(start, " %02x", *ptr);
+		ptr++; leng--;
+	}
+	start += sprintf(start, "\n");
+	return start;
+}
+
+static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
+{
+	if (start > end)
+		return start;
+	start += sprintf(start, "Interface:");
+	if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
+		start += sprintf(start, "%s: %s ", id, dev->stringindex[index]);
+	return start;
+}
+
+#endif /* PROC_EXTRA */
+
+/*****************************************************************/
+
+static char *usb_device_dump(char *start, char *end, const struct usb_device *usbdev,
+			     int bus, int level, int index, int count)
+{
+	int chix;
+	int cnt = 0;
+	int parent_devnum = 0;
+
+	if (level > MAX_TOPO_LEVEL)
+		return start;
+	if (usbdev->parent && usbdev->parent->devnum != -1)
+		parent_devnum = usbdev->parent->devnum;
+	/*
+	 * So the root hub's parent is 0 and any device that is
+	 * plugged into the root hub has a parent of 0.
+	 */
+	start += sprintf(start, format_topo, bus, level, parent_devnum, index, count,
+			 usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
+	/*
+	 * level = topology-tier level;
+	 * parent_devnum = parent device number;
+	 * index = parent's connector number;
+	 * count = device count at this level
+	 */
+	/* do not dump descriptors for root hub */
+	if (usbdev->devnum >= 0)
+		start = usb_dump_desc(start, end, usbdev);
+	if (start > end)
+		return start + sprintf(start, "(truncated)\n");
+	/* Now look at all of this device's children. */
+	for (chix = 0; chix < usbdev->maxchild; chix++) {
+		if (start > end)
+			return start;
+		if (usbdev->children[chix])
+			start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt);
+	}
+	return start;
+}
+
+static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	struct list_head *buslist;
+	struct usb_bus *bus;
+	char *page, *end;
+	ssize_t ret = 0;
+	unsigned int pos, len;
+
+	if (*ppos < 0)
+		return -EINVAL;
+	if (nbytes <= 0)
+		return 0;
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EFAULT;
+        if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+                return -ENOMEM;
+	pos = *ppos;
+	/* enumerate busses */
+	for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
+		/* print bandwidth allocation */
+		bus = list_entry(buslist, struct usb_bus, bus_list);
+		len = sprintf(page, format_bandwidth, bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC,
+			      (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
+			      bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
+		end = usb_device_dump(page + len, page + (PAGE_SIZE - 100), bus->root_hub, bus->busnum, 0, 0, 0);
+		len = end - page;
+		if (len > pos) {
+			len -= pos;
+			if (len > nbytes)
+				len = nbytes;
+			if (copy_to_user(buf, page + pos, len)) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			nbytes -= len;
+			buf += len;
+			ret += len;
+			pos = 0;
+			*ppos += len;
+		} else
+			pos -= len;
+	}
+	free_page((unsigned long)page);
+	return ret;
+}
+
+static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usb_device_status *st = (struct usb_device_status *)file->private_data;
+	unsigned int mask = 0;
+	
+	if (!st) {
+		st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
+		if (!st)
+			return POLLIN;
+		/*
+		 * need to prevent the module from being unloaded, since
+		 * proc_unregister does not call the release method and
+		 * we would have a memory leak
+		 */
+		st->lastev = conndiscevcnt;
+		file->private_data = st;
+		mask = POLLIN;
+	}
+	if (file->f_mode & FMODE_READ)
+                poll_wait(file, &deviceconndiscwq, wait);
+	if (st->lastev != conndiscevcnt)
+		mask |= POLLIN;
+	st->lastev = conndiscevcnt;
+	return mask;
+}
+
+static int usb_device_open(struct inode *inode, struct file *file)
+{
+        file->private_data = NULL;
+        return 0;
+}
+
+static int usb_device_release(struct inode *inode, struct file *file)
+{
+	if (file->private_data) {
+		kfree(file->private_data);
+		file->private_data = NULL;
+	}
+
+        return 0;
+}
+
+static long long usb_device_lseek(struct file * file, long long offset, int orig)
+{
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		return file->f_pos;
+
+	case 1:
+		file->f_pos += offset;
+		return file->f_pos;
+
+	case 2:
+		return -EINVAL;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+struct file_operations usbdevfs_devices_fops = {
+	usb_device_lseek,   /* lseek   */
+	usb_device_read,    /* read    */
+	NULL,               /* write   */
+	NULL,               /* readdir */
+	usb_device_poll,    /* poll    */
+	NULL,               /* ioctl   */
+	NULL,               /* mmap    */
+	usb_device_open,    /* open    */
+	NULL,               /* flush   */
+	usb_device_release, /* release */
+	NULL                /* fsync   */
+};
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/devio.c linux/drivers/usb/devio.c
--- v2.3.38/linux/drivers/usb/devio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/devio.c	Mon Jan 10 11:32:48 2000
@@ -0,0 +1,889 @@
+/*****************************************************************************/
+
+/*
+ *      devio.c  --  User space communication with USB devices.
+ *
+ *      Copyright (C) 1999-2000  Thomas Sailer (sailer@ife.ee.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
+ *      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.
+ *
+ *  This file implements the usbdevfs/x/y files, where
+ *  x is the bus number and y the device number.
+ *
+ *  It allows user space programs/"drivers" to communicate directly
+ *  with USB devices without intervening kernel driver.
+ *
+ *  Revision history
+ *    22.12.1999   0.1   Initial release (split from proc_usb.c)
+ *    04.01.2000   0.2   Turned into its own filesystem
+ */
+
+/*****************************************************************************/
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/signal.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+struct async {
+        struct list_head asynclist;
+        struct dev_state *ps;
+	struct task_struct *task;
+	unsigned int signr;
+	void *userbuffer;
+        void *userurb;
+        urb_t urb;
+};
+
+static long long usbdev_lseek(struct file *file, long long offset, int orig)
+{
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		return file->f_pos;
+
+	case 1:
+		file->f_pos += offset;
+		return file->f_pos;
+
+	case 2:
+		return -EINVAL;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t *ppos)
+{
+	struct dev_state *ps = (struct dev_state *)file->private_data;
+	ssize_t ret = 0;
+	unsigned len;
+	loff_t pos;
+
+	pos = *ppos;
+	down_read(&ps->devsem);
+	if (!ps->dev)
+		ret = -ENODEV;
+	else if (pos < 0)
+		ret = -EINVAL;
+	else if (pos < sizeof(struct usb_device_descriptor)) {
+		len = sizeof(struct usb_device_descriptor) - pos;
+		if (len > nbytes)
+			len = nbytes;
+		if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len))
+			ret = -EFAULT;
+		else {
+			*ppos += len;
+			buf += len;
+			nbytes -= len;
+			ret += len;
+		}
+	}
+	up_read(&ps->devsem);
+	return ret;
+}
+
+extern inline unsigned int ld2(unsigned int x)
+{
+        unsigned int r = 0;
+        
+        if (x >= 0x10000) {
+                x >>= 16;
+                r += 16;
+        }
+        if (x >= 0x100) {
+                x >>= 8;
+                r += 8;
+        }
+        if (x >= 0x10) {
+                x >>= 4;
+                r += 4;
+        }
+        if (x >= 4) {
+                x >>= 2;
+                r += 2;
+        }
+        if (x >= 2)
+                r++;
+        return r;
+}
+
+/*
+ * async list handling
+ */
+
+static struct async *alloc_async(unsigned int numisoframes)
+{
+        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
+        struct async *as = kmalloc(assize, GFP_KERNEL);
+        if (!as)
+                return NULL;
+        memset(as, 0, assize);
+        as->urb.number_of_packets = numisoframes;
+        return as;
+}
+
+static void free_async(struct async *as)
+{
+        if (as->urb.transfer_buffer)
+                kfree(as->urb.transfer_buffer);
+        kfree(as);
+}
+
+extern __inline__ void async_newpending(struct async *as)
+{
+        struct dev_state *ps = as->ps;
+        unsigned long flags;
+        
+        spin_lock_irqsave(&ps->lock, flags);
+        list_add_tail(&as->asynclist, &ps->async_pending);
+        spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+extern __inline__ void async_removepending(struct async *as)
+{
+        struct dev_state *ps = as->ps;
+        unsigned long flags;
+        
+        spin_lock_irqsave(&ps->lock, flags);
+        list_del(&as->asynclist);
+        INIT_LIST_HEAD(&as->asynclist);
+        spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
+{
+        unsigned long flags;
+        struct async *as = NULL;
+
+        spin_lock_irqsave(&ps->lock, flags);
+        if (!list_empty(&ps->async_completed)) {
+                as = list_entry(ps->async_completed.next, struct async, asynclist);
+                list_del(&as->asynclist);
+                INIT_LIST_HEAD(&as->asynclist);
+        }
+        spin_unlock_irqrestore(&ps->lock, flags);
+        return as;
+}
+
+extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb)
+{
+        unsigned long flags;
+        struct async *as;
+        struct list_head *p;
+
+        spin_lock_irqsave(&ps->lock, flags);
+        for (p = ps->async_pending.next; p != &ps->async_pending; ) {
+                as = list_entry(p, struct async, asynclist);
+                p = p->next;
+                if (as->userurb != userurb)
+                        continue;
+                list_del(&as->asynclist);
+                INIT_LIST_HEAD(&as->asynclist);
+                spin_unlock_irqrestore(&ps->lock, flags);
+                return as;
+        }
+        spin_unlock_irqrestore(&ps->lock, flags);
+        return NULL;
+}
+
+static void async_completed(purb_t urb)
+{
+        struct async *as = (struct async *)urb->context;
+        struct dev_state *ps = as->ps;
+	struct siginfo sinfo;
+
+#if 0
+	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);
+        spin_unlock(&ps->lock);
+        wake_up(&ps->wait);
+	if (as->signr) {
+		sinfo.si_signo = as->signr;
+		sinfo.si_errno = as->urb.status;
+		sinfo.si_code = SI_ASYNCIO;
+		sinfo.si_addr = as->userurb;
+		send_sig_info(as->signr, &sinfo, as->task);
+	}
+}
+
+static void destroy_all_async(struct dev_state *ps)
+{
+        struct async *as;
+        unsigned long flags;
+
+        spin_lock_irqsave(&ps->lock, flags);
+        if (!list_empty(&ps->async_pending)) {
+                as = list_entry(ps->async_pending.next, struct async, asynclist);
+                list_del(&as->asynclist);
+                INIT_LIST_HEAD(&as->asynclist);
+                spin_unlock_irqrestore(&ps->lock, flags);
+                /* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
+                usb_unlink_urb(&as->urb);
+                spin_lock_irqsave(&ps->lock, flags);
+        }
+        spin_unlock_irqrestore(&ps->lock, flags);
+        while ((as = async_getcompleted(ps)))
+                free_async(as);
+}
+
+/*
+ * interface claiming
+ */
+
+static void *driver_probe(struct usb_device *dev, unsigned int intf)
+{
+	return NULL;
+}
+
+static void driver_disconnect(struct usb_device *dev, void *context)
+{
+	struct dev_state *ps = (struct dev_state *)context;
+
+	ps->ifclaimed = 0;
+}
+
+struct usb_driver usbdevfs_driver = {
+	"usbdevfs",
+	driver_probe,
+	driver_disconnect,
+	LIST_HEAD_INIT(usbdevfs_driver.driver_list),
+	NULL,
+	0
+};
+
+static int claimintf(struct dev_state *ps, unsigned int intf)
+{
+	struct usb_device *dev = ps->dev;
+	struct usb_interface *iface;
+	int err;
+
+	if (intf >= 8*sizeof(ps->ifclaimed) || !dev || intf >= dev->actconfig->bNumInterfaces)
+		return -EINVAL;
+	/* already claimed */
+	if (test_bit(intf, &ps->ifclaimed))
+		return 0;
+	iface = &dev->actconfig->interface[intf];
+	err = -EBUSY;
+	lock_kernel();
+	if (!usb_interface_claimed(iface)) {
+		usb_driver_claim_interface(&usbdevfs_driver, iface, ps);
+		set_bit(intf, &ps->ifclaimed);
+		err = 0;
+	}
+	unlock_kernel();
+	return err;
+}
+
+static int releaseintf(struct dev_state *ps, unsigned int intf)
+{
+	struct usb_device *dev;
+	struct usb_interface *iface;
+	int err;
+
+	if (intf >= 8*sizeof(ps->ifclaimed))
+		return -EINVAL;
+	err = -EINVAL;
+	lock_kernel();
+	dev = ps->dev;
+	if (dev && test_and_clear_bit(intf, &ps->ifclaimed)) {
+		iface = &dev->actconfig->interface[intf];
+		usb_driver_release_interface(&usbdevfs_driver, iface);
+		err = 0;
+	}
+	unlock_kernel();
+	return err;
+}
+
+static int checkintf(struct dev_state *ps, unsigned int intf)
+{
+	if (intf >= 8*sizeof(ps->ifclaimed))
+		return -EINVAL;
+	if (test_bit(intf, &ps->ifclaimed))
+		return 0;
+	/* if not yet claimed, claim it for the driver */
+	printk(KERN_WARNING "usbdevfs: process %d (%s) did not claim interface %u before use\n",
+	       current->pid, current->comm, intf);
+	return claimintf(ps, intf);
+}
+
+static int findintfep(struct usb_device *dev, unsigned int ep)
+{
+	unsigned int i, j, e;
+        struct usb_interface *iface;
+	struct usb_interface_descriptor *alts;
+	struct usb_endpoint_descriptor *endpt;
+
+	if (ep & ~(USB_DIR_IN|0xf))
+		return -EINVAL;
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+		iface = &dev->actconfig->interface[i];
+		for (j = 0; j < iface->num_altsetting; j++) {
+                        alts = &iface->altsetting[j];
+			for (e = 0; e < alts->bNumEndpoints; e++) {
+				endpt = &alts->endpoint[e];
+				if (endpt->bEndpointAddress == ep)
+					return i;
+			}
+		}
+	}
+	return -ENOENT; 
+}
+
+static int findintfif(struct usb_device *dev, unsigned int ifn)
+{
+	unsigned int i, j;
+        struct usb_interface *iface;
+	struct usb_interface_descriptor *alts;
+
+	if (ifn & ~0xff)
+		return -EINVAL;
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+		iface = &dev->actconfig->interface[i];
+		for (j = 0; j < iface->num_altsetting; j++) {
+                        alts = &iface->altsetting[j];
+			if (alts->bInterfaceNumber == ifn)
+				return i;
+		}
+	}
+	return -ENOENT; 
+}
+
+/*
+ * file operations
+ */
+static int usbdev_open(struct inode *inode, struct file *file)
+{
+	struct usb_device *dev;
+	struct dev_state *ps;
+	int ret;
+
+	/* 
+	 * no locking necessary here, as both sys_open (actually filp_open)
+	 * and the hub thread have the kernel lock
+	 * (still acquire the kernel lock for safety)
+	 */
+	lock_kernel();
+	ret = -ENOENT;
+	if (ITYPE(inode->i_ino) != IDEVICE)
+		goto out;
+	dev = inode->u.usbdev_i.p.dev;
+	if (!dev)
+		goto out;
+	ret = -ENOMEM;
+	if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
+		goto out;
+	ret = 0;
+	ps->dev = dev;
+	ps->file = file;
+	spin_lock_init(&ps->lock);
+	INIT_LIST_HEAD(&ps->async_pending);
+	INIT_LIST_HEAD(&ps->async_completed);
+	init_waitqueue_head(&ps->wait);
+	init_rwsem(&ps->devsem);
+	ps->discsignr = 0;
+	ps->disctask = current;
+	ps->disccontext = NULL;
+	ps->ifclaimed = 0;
+	wmb();
+	list_add_tail(&ps->list, &dev->filelist);
+	file->private_data = ps;
+ out:
+	unlock_kernel();
+        return ret;
+}
+
+static int usbdev_release(struct inode *inode, struct file *file)
+{
+	struct dev_state *ps = (struct dev_state *)file->private_data;
+	unsigned int i;
+
+	lock_kernel();
+	list_del(&ps->list);
+	INIT_LIST_HEAD(&ps->list);
+	if (ps->dev) {
+		for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
+			if (test_bit(i, &ps->ifclaimed))
+				releaseintf(ps, i);
+	}
+	unlock_kernel();
+	destroy_all_async(ps);
+	kfree(ps);
+        return 0;
+}
+
+static int proc_control(struct dev_state *ps, void *arg)
+{
+	struct usb_device *dev = ps->dev;
+	struct usbdevfs_ctrltransfer ctrl;
+	unsigned int tmo;
+	unsigned char *tbuf;
+	int i, ret;
+
+	copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
+	switch (ctrl.requesttype & 0x1f) {
+	case USB_RECIP_ENDPOINT:
+		if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0)
+			return ret;
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+		break;
+
+	case USB_RECIP_INTERFACE:
+		if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0)
+			return ret;
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+		break;
+	}
+	if (ctrl.length > PAGE_SIZE)
+		return -EINVAL;
+	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	tmo = (ctrl.timeout * HZ + 999) / 1000;
+	if (ctrl.requesttype & 0x80) {
+		if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) {
+			free_page((unsigned long)tbuf);
+			return -EINVAL;
+		}
+		i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+				    ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
+		if ((i > 0) && ctrl.length) {
+			copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
+		}
+	} else {
+		if (ctrl.length) {
+			copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT);
+		}
+		i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+				    ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
+	}
+	free_page((unsigned long)tbuf);
+	if (i<0) {
+		printk(KERN_DEBUG "usbdevfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n", 
+		       dev->devnum, ctrl.requesttype, ctrl.request, ctrl.length, i);
+	}
+	return i;
+}
+
+static int proc_bulk(struct dev_state *ps, void *arg)
+{
+	struct usb_device *dev = ps->dev;
+	struct usbdevfs_bulktransfer bulk;
+	unsigned int tmo, len1, pipe;
+	unsigned long len2;
+	unsigned char *tbuf;
+	int i, ret;
+
+	copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
+	if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	if (bulk.ep & USB_DIR_IN)
+		pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
+	else
+		pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
+	if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
+		return -EINVAL;
+	len1 = bulk.len;
+	if (len1 > PAGE_SIZE)
+		len1 = PAGE_SIZE;
+	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	tmo = (bulk.timeout * HZ + 999) / 1000;
+	if (bulk.ep & 0x80) {
+		if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
+			free_page((unsigned long)tbuf);
+			return -EINVAL;
+		}
+		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+		if (!i && len2) {
+			copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
+		}
+	} else {
+		if (len1) {
+			copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
+		}
+		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+	}
+	free_page((unsigned long)tbuf);
+	if (i < 0) {
+		printk(KERN_WARNING "usbdevfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n", 
+		       dev->devnum, bulk.ep, bulk.len, i);
+		return i;
+	}
+	return len2;
+}
+
+static int proc_resetep(struct dev_state *ps, void *arg)
+{
+	unsigned int ep;
+	int ret;
+
+	get_user_ret(ep, (unsigned int *)arg, -EFAULT);
+	if ((ret = findintfep(ps->dev, ep)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
+	return 0;
+}
+
+static int proc_setintf(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_setinterface setintf;
+	int ret;
+
+	copy_from_user_ret(&setintf, arg, sizeof(setintf), -EFAULT);
+	if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
+		return -EINVAL;
+	return 0;
+}
+
+static int proc_setconfig(struct dev_state *ps, void *arg)
+{
+	unsigned int u;
+
+	get_user_ret(u, (unsigned int *)arg, -EFAULT);
+	if (usb_set_configuration(ps->dev, u) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int proc_submiturb(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_urb uurb;
+	struct usbdevfs_iso_packet_desc *isopkt = NULL;
+	struct async *as;
+	unsigned int u, totlen, isofrmlen;
+	int ret;
+
+	copy_from_user_ret(&uurb, arg, sizeof(uurb), -EFAULT);
+	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD))
+		return -EINVAL;
+	if (!uurb.buffer)
+		return -EINVAL;
+	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
+		return -EINVAL;
+	if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	switch(uurb.type) {
+	case USBDEVFS_URB_TYPE_BULK:
+		uurb.number_of_packets = 0;
+		if (uurb.buffer_length > 8192)
+			return -EINVAL;
+		if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
+			return -EFAULT;
+		break;
+
+	case USBDEVFS_URB_TYPE_ISO:
+		/* arbitrary limit */
+		if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
+			return -EINVAL;
+		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
+		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
+			return -ENOMEM;
+		if (copy_from_user(isopkt, &((struct usbdevfs_urb *)arg)->iso_frame_desc, isofrmlen)) {
+			kfree(isopkt);
+			return -EFAULT;
+		}
+		for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+			if (isopkt[u].length > 1023) {
+				kfree(isopkt);
+				return -EINVAL;
+			}
+			totlen += isopkt[u].length;
+		}
+		if (totlen > 8192) {
+			kfree(isopkt);
+			return -ENOMEM;
+		}
+		uurb.buffer_length = totlen;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	if (!(as = alloc_async(uurb.number_of_packets))) {
+		if (isopkt)
+			kfree(isopkt);
+		return -ENOMEM;
+	}
+	if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+		if (isopkt)
+			kfree(isopkt);
+		free_async(as);
+		return -ENOMEM;
+	}
+        as->urb.next = NULL;
+        as->urb.dev = ps->dev;
+        as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
+        as->urb.transfer_flags = uurb.flags;
+	as->urb.transfer_buffer_length = uurb.buffer_length;
+	as->urb.start_frame = uurb.start_frame;
+	as->urb.number_of_packets = uurb.number_of_packets;
+        as->urb.context = as;
+        as->urb.complete = async_completed;
+	for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+		as->urb.iso_frame_desc[u].offset = totlen;
+		as->urb.iso_frame_desc[u].length = isopkt[u].length;
+		totlen += isopkt[u].length;
+	}
+	if (isopkt)
+		kfree(isopkt);
+	as->ps = ps;
+        as->userurb = arg;
+	if (uurb.endpoint & USB_DIR_IN)
+		as->userbuffer = uurb.buffer;
+	else
+		as->userbuffer = NULL;
+	as->signr = uurb.signr;
+	as->task = current;
+	if (!(uurb.endpoint & USB_DIR_IN)) {
+		if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
+			free_async(as);
+			return -EFAULT;
+		}
+	}
+        async_newpending(as);
+        if ((ret = usb_submit_urb(&as->urb))) {
+		printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
+                async_removepending(as);
+                free_async(as);
+                return ret;
+        }
+        return 0;
+}
+
+static int proc_unlinkurb(struct dev_state *ps, void *arg)
+{
+	struct async *as;
+
+	as = async_getpending(ps, arg);
+	if (!as)
+		return -EINVAL;
+	usb_unlink_urb(&as->urb);
+	return 0;
+}
+
+static int processcompl(struct async *as)
+{
+	unsigned int i;
+
+	if (as->userbuffer)
+		if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
+			return -EFAULT;
+	put_user_ret(as->urb.status, &((struct usbdevfs_urb *)as->userurb)->status, -EFAULT);
+	put_user_ret(as->urb.actual_length, &((struct usbdevfs_urb *)as->userurb)->actual_length, -EFAULT);
+	put_user_ret(as->urb.error_count, &((struct usbdevfs_urb *)as->userurb)->error_count, -EFAULT);
+	if (!(usb_pipeisoc(as->urb.pipe)))
+		return 0;
+	for (i = 0; i < as->urb.number_of_packets; i++) {
+		put_user_ret(as->urb.iso_frame_desc[i].actual_length, 
+			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length, 
+			     -EFAULT);
+		put_user_ret(as->urb.iso_frame_desc[i].status, 
+			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status, 
+			     -EFAULT);
+	}
+	return 0;
+}
+
+static int proc_reapurb(struct dev_state *ps, void *arg)
+{
+        DECLARE_WAITQUEUE(wait, current);
+	struct async *as = NULL;
+	void *addr;
+	int ret;
+
+	add_wait_queue(&ps->wait, &wait);
+	while (ps->dev) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		if ((as = async_getcompleted(ps)))
+			break;
+		if (signal_pending(current))
+			break;
+		up_read(&ps->devsem);
+		schedule();
+		down_read(&ps->devsem);
+	}
+	remove_wait_queue(&ps->wait, &wait);
+	set_current_state(TASK_RUNNING);
+	if (as) {
+		ret = processcompl(as);
+		addr = as->userurb;
+		free_async(as);
+		if (ret)
+			return ret;
+		put_user_ret(addr, (void **)arg, -EFAULT);
+		return 0;
+	}
+	if (signal_pending(current))
+		return -EINTR;
+	return -EIO;
+}
+
+static int proc_reapurbnonblock(struct dev_state *ps, void *arg)
+{
+	struct async *as;
+	void *addr;
+	int ret;
+
+	if (!(as = async_getcompleted(ps)))
+		return -EAGAIN;
+	ret = processcompl(as);
+	addr = as->userurb;
+	free_async(as);
+	if (ret)
+		return ret;
+	put_user_ret(addr, (void **)arg, -EFAULT);
+	return 0;
+}
+
+static int proc_disconnectsignal(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_disconnectsignal ds;
+
+	copy_from_user_ret(&ds, arg, sizeof(ds), -EFAULT);
+	if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX))
+		return -EINVAL;
+	ps->discsignr = ds.signr;
+	ps->disccontext = ds.context;
+	return 0;
+}
+
+static int proc_claiminterface(struct dev_state *ps, void *arg)
+{
+	unsigned int intf;
+	int ret;
+
+	get_user_ret(intf, (unsigned int *)arg, -EFAULT);
+	if ((ret = findintfif(ps->dev, intf)) < 0)
+		return ret;
+	return claimintf(ps, ret);
+}
+
+static int proc_releaseinterface(struct dev_state *ps, void *arg)
+{
+	unsigned int intf;
+	int ret;
+
+	get_user_ret(intf, (unsigned int *)arg, -EFAULT);
+	if ((ret = findintfif(ps->dev, intf)) < 0)
+		return ret;
+	return releaseintf(ps, intf);
+}
+
+static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct dev_state *ps = (struct dev_state *)file->private_data;
+	int ret = -ENOIOCTLCMD;
+
+	if (!(file->f_mode & FMODE_WRITE))
+		return -EPERM;
+	down_read(&ps->devsem);
+	if (!ps->dev) {
+		up_read(&ps->devsem);
+		return -ENODEV;
+	}
+	switch (cmd) {
+	case USBDEVFS_CONTROL:
+		ret = proc_control(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_BULK:
+		ret = proc_bulk(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_RESETEP:
+		ret = proc_resetep(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_SETINTERFACE:
+		ret = proc_setintf(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_SETCONFIGURATION:
+		ret = proc_setconfig(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_SUBMITURB:
+		ret = proc_submiturb(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_DISCARDURB:
+		ret = proc_unlinkurb(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_REAPURB:
+		ret = proc_reapurb(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_REAPURBNDELAY:
+		ret = proc_reapurbnonblock(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_DISCSIGNAL:
+		ret = proc_disconnectsignal(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_CLAIMINTERFACE:
+		ret = proc_claiminterface(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_RELEASEINTERFACE:
+		ret = proc_releaseinterface(ps, (void *)arg);
+		break;
+
+	}
+	up_read(&ps->devsem);
+	return ret;
+}
+
+static struct file_operations usbdevfs_device_file_operations = {
+	usbdev_lseek,    /* lseek   */
+	usbdev_read,     /* read    */
+	NULL,            /* write   */
+	NULL,            /* readdir */
+	NULL,            /* poll    */
+	usbdev_ioctl,    /* ioctl   */
+	NULL,            /* mmap    */
+	usbdev_open,     /* open    */
+	NULL,            /* flush   */
+	usbdev_release,  /* release */
+	NULL             /* fsync   */
+};
+
+struct inode_operations usbdevfs_device_inode_operations = {
+        &usbdevfs_device_file_operations,  /* file-ops */
+};
+
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/drivers.c linux/drivers/usb/drivers.c
--- v2.3.38/linux/drivers/usb/drivers.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/drivers.c	Mon Jan 10 11:32:48 2000
@@ -0,0 +1,124 @@
+/*
+ * drivers.c
+ * (C) Copyright 1999 Randy Dunlap.
+ * (C) Copyright 1999, 2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
+ * (C) Copyright 1999 Deti Fliegl (new USB architecture)
+ *
+ * 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
+ *
+ *************************************************************
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Converted the whole proc stuff to real
+ *   read methods. Now not the whole device list needs to fit
+ *   into one page, only the device list for one bus.
+ *   Added a poll method to /proc/bus/usb/devices, to wake
+ *   up an eventual usbd
+ * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Turned into its own filesystem
+ *
+ * $Id: proc_usb.c,v 1.16 1999/12/20 11:11:10 fliegl Exp $
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+
+/*****************************************************************/
+
+/*
+ * Dump usb_driver_list.
+ *
+ * We now walk the list of registered USB drivers.
+ */
+static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	struct list_head *tmp = usb_driver_list.next;
+	char *page, *start, *end;
+	ssize_t ret = 0;
+	unsigned int pos, len;
+
+	if (*ppos < 0)
+		return -EINVAL;
+	if (nbytes <= 0)
+		return 0;
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EFAULT;
+        if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+                return -ENOMEM;
+	start = page;
+	end = page + (PAGE_SIZE - 100);
+	pos = *ppos;
+	for (; tmp != &usb_driver_list; tmp = tmp->next) {
+		struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+		start += sprintf (start, "%s\n", driver->name);
+		if (start > end) {
+			start += sprintf(start, "(truncated)\n");
+			break;
+		}
+	}
+	if (start == page)
+		start += sprintf(start, "(none)\n");
+	len = start - page;
+	if (len > pos) {
+		len -= pos;
+		if (len > nbytes)
+			len = nbytes;
+		ret = len;
+		if (copy_to_user(buf, page + pos, len))
+			ret = -EFAULT;
+		else
+			*ppos += len;
+	}
+	free_page((unsigned long)page);
+	return ret;
+}
+
+static long long usb_driver_lseek(struct file * file, long long offset, int orig)
+{
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		return file->f_pos;
+
+	case 1:
+		file->f_pos += offset;
+		return file->f_pos;
+
+	case 2:
+		return -EINVAL;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+struct file_operations usbdevfs_drivers_fops = {
+	usb_driver_lseek, /* lseek   */
+	usb_driver_read,  /* read    */
+	NULL,             /* write   */
+	NULL,             /* readdir */
+	NULL,             /* poll    */
+	NULL,             /* ioctl   */
+	NULL,             /* mmap    */
+	NULL,             /* open    */
+	NULL,             /* flush   */
+	NULL,             /* release */
+	NULL              /* fsync   */
+};
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/hid.c linux/drivers/usb/hid.c
--- v2.3.38/linux/drivers/usb/hid.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/hid.c	Sat Jan  8 21:36:48 2000
@@ -38,7 +38,6 @@
 #include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
-#include <linux/config.h>
 #include <linux/spinlock.h>
 
 #undef DEBUG
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.3.38/linux/drivers/usb/inode.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/inode.c	Mon Jan 10 11:32:48 2000
@@ -0,0 +1,722 @@
+/*****************************************************************************/
+
+/*
+ *	inode.c  --  Inode/Dentry functions for the USB device file system.
+ *
+ *	Copyright (C) 2000
+ *          Thomas Sailer (sailer@ife.ee.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
+ *	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.
+ *
+ *  History:
+ *   0.1  04.01.2000  Created
+ *
+ *  $Id: ezusb.c,v 1.22 1999/12/03 15:06:28 tom Exp $
+ */
+
+/*****************************************************************************/
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#include "usb.h"
+#include "usbdevice_fs.h"
+
+/* --------------------------------------------------------------------- */
+
+static LIST_HEAD(superlist);
+
+extern struct inode_operations usbdevfs_bus_inode_operations;
+
+static struct inode_operations devices_inode_operations = {
+        &usbdevfs_devices_fops
+};
+
+static struct inode_operations drivers_inode_operations = {
+        &usbdevfs_drivers_fops
+};
+
+struct special {
+	const char *name;
+	struct inode_operations *iops;
+	struct list_head inodes;
+};
+
+static struct special special[] = { 
+	{ "devices", &devices_inode_operations,  },
+	{ "drivers", &drivers_inode_operations,  }
+};
+
+#define NRSPECIAL (sizeof(special)/sizeof(special[0]))
+
+/* --------------------------------------------------------------------- */
+
+static int dnumber(struct dentry *dentry)
+{
+	const char *name;
+	unsigned int s;
+
+	if (dentry->d_name.len != 3)
+		return -1;
+	name = dentry->d_name.name;
+	if (name[0] < '0' || name[0] > '9' ||
+	    name[1] < '0' || name[1] > '9' ||
+	    name[2] < '0' || name[2] > '9')
+		return -1;
+	s = name[0] - '0';
+	s = s * 10 + name[1] - '0';
+	s = s * 10 + name[2] - '0';
+	return s;
+}
+
+/*
+ * utility functions; should be called with the kernel lock held
+ * to protect against busses/devices appearing/disappearing
+ */
+
+static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
+{
+	struct inode *inode;
+	unsigned int devnum = dev->devnum;
+	unsigned int busnum = dev->bus->busnum;
+
+	if (devnum < 1 || devnum > 127 || busnum > 255)
+		return;
+	inode = iget(sb, IDEVICE | (busnum << 8) | devnum);
+	if (!inode) {
+		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum);
+		return;
+	}
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_uid = sb->u.usbdevfs_sb.devuid;
+	inode->i_gid = sb->u.usbdevfs_sb.devgid;
+	inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
+	inode->i_op = &usbdevfs_device_inode_operations;
+	inode->i_size = sizeof(struct usb_device_descriptor);
+	inode->u.usbdev_i.p.dev = dev;
+	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
+	list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes);
+}
+
+static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb)
+{
+	unsigned int i;
+
+	if (!dev)
+		return;
+	new_dev_inode(dev, sb);
+	for (i = 0; i < dev->maxchild; i++) {
+                if (!dev->children[i])
+                        continue;
+		recurse_new_dev_inode(dev->children[i], sb);
+	}
+}
+
+static void new_bus_inode(struct usb_bus *bus, struct super_block *sb)
+{
+	struct inode *inode;
+	unsigned int busnum = bus->busnum;
+
+	if (busnum > 255)
+		return;
+	inode = iget(sb, IBUS | (busnum << 8));
+	if (!inode) {
+		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum);
+		return;
+	}
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_uid = sb->u.usbdevfs_sb.busuid;
+	inode->i_gid = sb->u.usbdevfs_sb.busgid;
+	inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR;
+	inode->i_op = &usbdevfs_bus_inode_operations;
+	inode->u.usbdev_i.p.bus = bus;
+	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
+	list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);
+}
+
+static void free_inode(struct inode *inode)
+{
+	inode->u.usbdev_i.p.bus = NULL;
+	inode->u.usbdev_i.p.dev = NULL;
+	inode->i_mode &= ~S_IRWXUGO;
+	inode->i_uid = inode->i_gid = 0;
+	inode->i_op = NULL;
+	inode->i_size = 0;
+	list_del(&inode->u.usbdev_i.slist);
+	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
+	list_del(&inode->u.usbdev_i.dlist);
+	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
+	iput(inode);
+}
+
+static struct usb_bus *usbdevfs_findbus(int busnr)
+{
+        struct list_head *list;
+        struct usb_bus *bus;
+
+        for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
+                bus = list_entry(list, struct usb_bus, bus_list);
+                if (bus->busnum == busnr)
+                        return bus;
+        }
+        return NULL;
+}
+
+#if 0
+static struct usb_device *finddev(struct usb_device *dev, int devnr)
+{
+        unsigned int i;
+        struct usb_device *d2;
+
+        if (!dev)
+                return NULL;
+        if (dev->devnum == devnr)
+                return dev;
+        for (i = 0; i < dev->maxchild; i++) {
+                if (!dev->children[i])
+                        continue;
+                if ((d2 = finddev(dev->children[i], devnr)))
+                        return d2;
+        }
+        return NULL;
+}
+
+static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr)
+{
+        return finddev(bus->root_hub, devnr);
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+static int usbdevfs_revalidate(struct dentry *dentry, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+
+        if (!inode)
+                return 0;
+	if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus)
+		return 0;
+	if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev)
+		return 0;
+	return 1;
+}
+
+static struct dentry_operations usbdevfs_dentry_operations = {
+        usbdevfs_revalidate,    /* d_revalidate */
+        NULL,                   /* d_hash */
+        NULL,                   /* d_compare */
+};
+
+static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry)
+{
+	int busnr;
+	unsigned long ino = 0;
+	unsigned int i;
+	struct inode *inode;
+
+	/* sanity check */
+	if (dir->i_ino != IROOT)
+		return ERR_PTR(-EINVAL);
+	dentry->d_op = &usbdevfs_dentry_operations;
+	busnr = dnumber(dentry);
+	if (busnr >= 0 && busnr <= 255)
+		ino = IBUS | (busnr << 8);
+	if (!ino) {
+		for (i = 0; i < NRSPECIAL; i++) {
+			if (strlen(special[i].name) == dentry->d_name.len && 
+			    !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) {
+				ino = ISPECIAL | (i + IROOT + 1);
+				break;
+			}
+		}
+	}
+	if (!ino)
+		return ERR_PTR(-ENOENT);
+	inode = iget(dir->i_sb, ino);
+	if (!inode)
+		return ERR_PTR(-EINVAL);
+	if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) {
+		iput(inode);
+		inode = NULL;
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode;
+	int devnr;
+
+	/* sanity check */
+	if (ITYPE(dir->i_ino) != IBUS)
+		return ERR_PTR(-EINVAL);
+	dentry->d_op = &usbdevfs_dentry_operations;
+	devnr = dnumber(dentry);
+	if (devnr < 1 || devnr > 127)
+		return ERR_PTR(-ENOENT);
+	inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr);
+	if (!inode)
+		return ERR_PTR(-EINVAL);
+	if (inode && inode->u.usbdev_i.p.dev == NULL) {
+		iput(inode);
+		inode = NULL;
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	unsigned long ino = inode->i_ino;
+	struct special *spec;
+	struct list_head *list;
+	struct usb_bus *bus;
+	char numbuf[8];
+	unsigned int i;
+
+	/* sanity check */
+	if (ino != IROOT)
+		return -EINVAL;
+	i = filp->f_pos;
+	switch (i) {
+	case 0:
+		if (filldir(dirent, ".", 1, i, IROOT) < 0)
+			return 0;
+		filp->f_pos++;
+		i++;
+		/* fall through */
+
+	case 1:
+		if (filldir(dirent, "..", 2, i, IROOT) < 0)
+			return 0;
+		filp->f_pos++;
+		i++;
+		/* fall through */
+
+	default:
+		
+		while (i >= 2 && i < 2+NRSPECIAL) {
+			spec = &special[filp->f_pos-2];
+			if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0)
+				return 0;
+			filp->f_pos++;
+			i++;
+		}
+		if (i < 2+NRSPECIAL)
+			return 0;
+		i -= 2+NRSPECIAL;
+		lock_kernel();
+		for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
+			if (i > 0) {
+				i--;
+				continue;
+			}
+			bus = list_entry(list, struct usb_bus, bus_list);
+			sprintf(numbuf, "%03d", bus->busnum);
+			if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0)
+				break;
+			filp->f_pos++;
+		}
+		unlock_kernel();
+		return 0;
+	}
+}
+
+static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir)
+{
+	char numbuf[8];
+	unsigned int i;
+
+	if (!dev)
+		return pos;
+	sprintf(numbuf, "%03d", dev->devnum);
+	if (pos > 0)
+		pos--;
+	else {
+		if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0)
+			return -1;
+		filp->f_pos++;
+	}
+	for (i = 0; i < dev->maxchild; i++) {
+		if (!dev->children[i])
+			continue;
+		pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir);
+		if (pos < 0)
+			return -1;
+	}
+	return pos;
+}
+
+static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	unsigned long ino = inode->i_ino;
+	struct usb_bus *bus;
+
+	/* sanity check */
+	if (ITYPE(ino) != IBUS)
+		return -EINVAL;
+	switch ((unsigned int)filp->f_pos) {
+	case 0:
+		if (filldir(dirent, ".", 1, filp->f_pos, ino) < 0)
+			return 0;
+		filp->f_pos++;
+		/* fall through */
+
+	case 1:
+		if (filldir(dirent, "..", 2, filp->f_pos, IROOT) < 0)
+			return 0;
+		filp->f_pos++;
+		/* fall through */
+
+	default:
+		lock_kernel();
+		bus = usbdevfs_findbus(IBUSNR(ino));
+		bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), filp->f_pos-2, filp, dirent, filldir);
+		unlock_kernel();
+		return 0;
+	}
+}
+
+static struct file_operations usbdevfs_root_file_operations = {
+	readdir: usbdevfs_root_readdir
+};
+
+static struct inode_operations usbdevfs_root_inode_operations = {
+	default_file_ops: &usbdevfs_root_file_operations,
+	lookup: usbdevfs_root_lookup
+};
+
+static struct file_operations usbdevfs_bus_file_operations = {
+	readdir: usbdevfs_bus_readdir
+};
+
+static struct inode_operations usbdevfs_bus_inode_operations = {
+	default_file_ops: &usbdevfs_bus_file_operations,
+	lookup: usbdevfs_bus_lookup
+};
+
+static void usbdevfs_read_inode(struct inode *inode)
+{
+	struct special *spec;
+
+	inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME;
+	inode->i_mode = S_IFREG;
+	inode->i_gid = inode->i_uid = 0;
+	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
+	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
+	inode->u.usbdev_i.p.dev = NULL;
+	inode->u.usbdev_i.p.bus = NULL;
+	switch (ITYPE(inode->i_ino)) {
+	case ISPECIAL:
+		if (inode->i_ino == IROOT) {
+			inode->i_op = &usbdevfs_root_inode_operations;
+			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+			return;
+		}
+		if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL)
+			return;
+		spec = &special[inode->i_ino-(IROOT+1)];
+		inode->i_op = spec->iops;
+		return;
+
+	case IDEVICE:
+		return;
+
+	case IBUS:
+		return;
+
+	default:
+		return;
+        }
+}
+
+static void usbdevfs_put_inode(struct inode *inode)
+{
+}
+
+static void usbdevfs_put_super(struct super_block *sb)
+{
+	list_del(&sb->u.usbdevfs_sb.slist);
+	INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist);
+	while (!list_empty(&sb->u.usbdevfs_sb.ilist))
+		free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist));
+        MOD_DEC_USE_COUNT;
+}
+
+static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+        struct statfs tmp;
+
+        tmp.f_type = USBDEVICE_SUPER_MAGIC;
+        tmp.f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
+        tmp.f_blocks = 0;
+        tmp.f_bfree = 0;
+        tmp.f_bavail = 0;
+        tmp.f_files = 0;
+        tmp.f_ffree = 0;
+        tmp.f_namelen = NAME_MAX;
+        return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static struct super_operations usbdevfs_sops = { 
+        usbdevfs_read_inode,
+        NULL,
+        usbdevfs_put_inode,
+        NULL,
+        NULL,
+        usbdevfs_put_super,
+        NULL,
+        usbdevfs_statfs,
+        NULL
+};
+
+struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent)
+{
+        struct inode *root_inode, *inode;
+	struct list_head *blist;
+	struct usb_bus *bus;
+	unsigned int i;
+	uid_t devuid = 0, busuid = 0, listuid = 0;
+	gid_t devgid = 0, busgid = 0, listgid = 0;
+	umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO;
+	char *curopt = NULL, *value;
+
+	/* parse options */
+	if (data)
+		curopt = strtok(data, ",");
+	for (; curopt; curopt = strtok(NULL, ",")) {
+		if ((value = strchr(curopt, '=')) != NULL)
+			*value++ = 0;
+		if (!strcmp(curopt, "devuid")) {
+			if (!value || !value[0])
+				goto opterr;
+			devuid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "devgid")) {
+			if (!value || !value[0])
+				goto opterr;
+			devgid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "devmode")) {
+			if (!value || !value[0])
+				goto opterr;
+			devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "busuid")) {
+			if (!value || !value[0])
+				goto opterr;
+			busuid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "busgid")) {
+			if (!value || !value[0])
+				goto opterr;
+			busgid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "busmode")) {
+			if (!value || !value[0])
+				goto opterr;
+			busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "listuid")) {
+			if (!value || !value[0])
+				goto opterr;
+			listuid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "listgid")) {
+			if (!value || !value[0])
+				goto opterr;
+			listgid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "listmode")) {
+			if (!value || !value[0])
+				goto opterr;
+			listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+			if (*value)
+				goto opterr;
+		}
+	}
+	/* fill superblock */
+        MOD_INC_USE_COUNT;
+        lock_super(s);
+        s->s_blocksize = 1024;
+        s->s_blocksize_bits = 10;
+        s->s_magic = USBDEVICE_SUPER_MAGIC;
+        s->s_op = &usbdevfs_sops;
+	INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist);
+	INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist);
+	s->u.usbdevfs_sb.devuid = devuid;
+	s->u.usbdevfs_sb.devgid = devgid;
+	s->u.usbdevfs_sb.devmode = devmode;
+	s->u.usbdevfs_sb.busuid = busuid;
+	s->u.usbdevfs_sb.busgid = busgid;
+	s->u.usbdevfs_sb.busmode = busmode;
+	root_inode = iget(s, IROOT);
+        if (!root_inode)
+                goto out_no_root;
+        s->s_root = d_alloc_root(root_inode);
+        if (!s->s_root)
+                goto out_no_root;
+	list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
+	unlock_super(s);
+	for (i = 0; i < NRSPECIAL; i++) {
+		if (!(inode = iget(s, IROOT+1+i)))
+			continue;
+		inode->i_uid = listuid;
+		inode->i_gid = listgid;
+		inode->i_mode = listmode | S_IFREG;
+		list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
+		list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
+	}
+	lock_kernel();
+	for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
+		bus = list_entry(blist, struct usb_bus, bus_list);
+		new_bus_inode(bus, s);
+		recurse_new_dev_inode(bus->root_hub, s);
+	}
+	unlock_kernel();
+        return s;
+
+ out_no_root:
+        printk("usbdevfs_read_super: get root inode failed\n");
+        iput(root_inode);
+        s->s_dev = 0;
+        unlock_super(s);
+	MOD_DEC_USE_COUNT;
+        return NULL;
+
+ opterr:
+        printk(KERN_WARNING "usbdevfs: mount parameter error\n");
+	s->s_dev = 0;
+	return NULL;
+}
+
+static struct file_system_type usbdevice_fs_type = {
+        "usbdevfs",
+        0,
+        usbdevfs_read_super,
+        NULL
+};
+
+/* --------------------------------------------------------------------- */
+
+void usbdevfs_add_bus(struct usb_bus *bus)
+{
+	struct list_head *slist;
+
+	lock_kernel();
+	for (slist = superlist.next; slist != &superlist; slist = slist->next)
+		new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_remove_bus(struct usb_bus *bus)
+{
+	lock_kernel();
+	while (!list_empty(&bus->inodes))
+		free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_add_device(struct usb_device *dev)
+{
+	struct list_head *slist;
+
+	lock_kernel();
+	for (slist = superlist.next; slist != &superlist; slist = slist->next)
+		new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_remove_device(struct usb_device *dev)
+{
+	struct dev_state *ds;
+	struct siginfo sinfo;
+
+	lock_kernel();
+	while (!list_empty(&dev->inodes))
+		free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist));
+	while (!list_empty(&dev->filelist)) {
+		ds = list_entry(dev->filelist.next, struct dev_state, list);
+		list_del(&ds->list);
+		INIT_LIST_HEAD(&ds->list);
+		down_write(&ds->devsem);
+		ds->dev = NULL;
+		up_write(&ds->devsem);
+		if (ds->discsignr) {
+			sinfo.si_signo = SIGPIPE;
+			sinfo.si_errno = EPIPE;
+			sinfo.si_code = SI_ASYNCIO;
+			sinfo.si_addr = ds->disccontext;
+			send_sig_info(ds->discsignr, &sinfo, ds->disctask);
+		}
+	}
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+/* --------------------------------------------------------------------- */
+
+int __init usbdevfs_init(void)
+{
+	int ret;
+
+	for (ret = 0; ret < NRSPECIAL; ret++) {
+		INIT_LIST_HEAD(&special[ret].inodes);
+	}
+	if ((ret = usb_register(&usbdevfs_driver)))
+		return ret;
+	if ((ret = register_filesystem(&usbdevice_fs_type)))
+		usb_deregister(&usbdevfs_driver);
+	return ret;
+}
+
+void __exit usbdevfs_cleanup(void)
+{
+	usb_deregister(&usbdevfs_driver);
+	unregister_filesystem(&usbdevice_fs_type);
+}
+
+#if 0
+module_init(usbdevfs_init);
+module_exit(usbdevfs_cleanup);
+#endif
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/keybdev.c linux/drivers/usb/keybdev.c
--- v2.3.38/linux/drivers/usb/keybdev.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/keybdev.c	Mon Jan 10 11:35:09 2000
@@ -43,11 +43,11 @@
 	  0x26, 0x25, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x00,
 	  0x23, 0x24, 0x25, 0x26, 0x27 };
 
-#elif CONFIG_MAC_KEYBOARD
+#elif CONFIG_ADB_KEYBOARD
 
 static unsigned char keybdev_mac_codes[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,  0,  1,
+	 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, 55, 49, 57,122,120, 99,118, 96,
 	 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
@@ -85,10 +85,10 @@
 		}
 	} else handle_scancode(code, down);
 
-#elif CONFIG_MAC_KEYBOARD
+#elif CONFIG_ADB_KEYBOARD
 
-	if (keycode < 128 && keybdev_mac_codes[code]) 
-		handle_scancode(keybdev_mac_codes[code], down);
+	if (code < 128 && keybdev_mac_codes[code]) 
+		handle_scancode(keybdev_mac_codes[code] & 0x7f, down);
 	else
 		printk(KERN_WARNING "keybdev.c: can't emulate keycode %d\n", code);
 
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/mousedev.c linux/drivers/usb/mousedev.c
--- v2.3.38/linux/drivers/usb/mousedev.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/mousedev.c	Mon Jan 10 11:37:53 2000
@@ -83,7 +83,7 @@
 				switch (code) {
 					case REL_X:	list->dx += value; break;
 					case REL_Y:	list->dy -= value; break;
-					case REL_WHEEL:	if (list->mode) list->dz += value; break;
+					case REL_WHEEL:	if (list->mode) list->dz -= value; break;
 				}
 				break;
 
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.3.38/linux/drivers/usb/ov511.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/ov511.c	Mon Jan 10 11:37:53 2000
@@ -63,13 +63,13 @@
 
 #define OV511_I2C_RETRIES 3
 
-/* Video Size 384 x 288 x 3 bytes for RGB */
-#define MAX_FRAME_SIZE (320 * 240 * 3)
+/* Video Size 640 x 480 x 3 bytes for RGB */
+#define MAX_FRAME_SIZE (640 * 480 * 3)
 
 // FIXME - Force CIF to make some apps happy for the moment. Should find a 
 //         better way to do this.
-#define DEFAULT_WIDTH 320
-#define DEFAULT_HEIGHT 240
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
 
 char kernel_version[] = UTS_RELEASE;
 
@@ -200,7 +200,9 @@
 		USB_TYPE_CLASS | USB_RECIP_DEVICE,
 		0, (__u16)reg, &value, 1, HZ);	
 			
+#if 0
 	PDEBUG("reg write: 0x%02X:0x%02X\n", reg, value);
+#endif
 			
 	return rc;
 }
@@ -217,7 +219,9 @@
 		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
 		0, (__u16)reg, buffer, 1, HZ);
                                
+#if 0
 	PDEBUG("reg read: 0x%02X:0x%02X\n", reg, buffer[0]);
+#endif
 	
 	if(rc < 0)
 		return rc;
@@ -229,7 +233,9 @@
 {
 	int rc, retries;
 
+#if 0
 	PDEBUG("i2c write: 0x%02X:0x%02X\n", reg, value);
+#endif
 	/* Three byte write cycle */
 	for(retries = OV511_I2C_RETRIES;;) {
 		/* Select camera register */
@@ -309,7 +315,9 @@
 	}
 
 	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+#if 0
 	PDEBUG("i2c read: 0x%02X:0x%02X\n", reg, value);
+#endif
 		
 	/* This is needed to make ov511_i2c_write() work */
 	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
@@ -318,6 +326,54 @@
 	return (value);
 }
 
+static void ov511_dump_i2c_range( struct usb_device *dev, int reg1, int regn)
+{
+	int i;
+	int rc;
+	for(i=reg1; i<=regn; i++) {
+	  rc = ov511_i2c_read(dev, i);
+	}
+}
+
+static void ov511_dump_i2c_regs( struct usb_device *dev)
+{
+	PDEBUG("I2C REGS\n");
+	ov511_dump_i2c_range(dev, 0x00, 0x38);
+}
+
+static void ov511_dump_reg_range( struct usb_device *dev, int reg1, int regn)
+{
+	int i;
+	int rc;
+	for(i=reg1; i<=regn; i++) {
+	  rc = ov511_reg_read(dev, i);
+	  PDEBUG("OV511[0x%X] = 0x%X\n", i, rc);
+	}
+}
+
+static void ov511_dump_regs( struct usb_device *dev)
+{
+	PDEBUG("CAMERA INTERFACE REGS\n");
+	ov511_dump_reg_range(dev, 0x10, 0x1f);
+	PDEBUG("DRAM INTERFACE REGS\n");
+	ov511_dump_reg_range(dev, 0x20, 0x23);
+	PDEBUG("ISO FIFO REGS\n");
+	ov511_dump_reg_range(dev, 0x30, 0x31);
+	PDEBUG("PIO REGS\n");
+	ov511_dump_reg_range(dev, 0x38, 0x39);
+	ov511_dump_reg_range(dev, 0x3e, 0x3e);
+	PDEBUG("I2C REGS\n");
+	ov511_dump_reg_range(dev, 0x40, 0x49);
+	PDEBUG("SYSTEM CONTROL REGS\n");
+	ov511_dump_reg_range(dev, 0x50, 0x53);
+	ov511_dump_reg_range(dev, 0x5e, 0x5f);
+	PDEBUG("OmniCE REGS\n");
+	ov511_dump_reg_range(dev, 0x70, 0x79);
+	ov511_dump_reg_range(dev, 0x80, 0x9f);
+	ov511_dump_reg_range(dev, 0xa0, 0xbf);
+
+}
+
 int ov511_reset(struct usb_device *dev, unsigned char reset_type)
 {
 	int rc;
@@ -399,8 +455,68 @@
 	return 0;
 }
 
-/* How much data is left in the scratch buf? */
-#define scratch_left(x)	(ov511->scratchlen - (int)((char *)x - (char *)ov511->scratch))
+/***************************************************************
+
+For a 640x480 images, data shows up in 1200 384 byte segments.  The
+first 128 bytes of each segment are probably some combo of UV but I
+haven't figured it out yet.  The next 256 bytes are apparently Y
+data and represent 4 squares of 8x8 pixels as follows:
+
+  0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+  8  9 ... 15    72  73 ...  79        200 201 ... 207
+       ...              ...                    ...
+ 56 57 ... 63   120 121     127        248 249 ... 255
+
+Right now I'm only moving the Y data and haven't figured out
+the UV data.
+
+If OV511_DUMPPIX is defined, _parse_data just dumps the
+incoming segments, verbatim, in order, into the frame.
+When used with vidcat -f ppm -s 640x480 this puts the data
+on the standard output and can be analyzed with the parseppm.c
+utility I wrote.  That's a much faster way for figuring out how
+this data is scrambled.
+
+****************************************************************/ 
+
+static void ov511_parse_data(unsigned char * pIn,
+			    unsigned char * pOut,
+			    int iSegment)
+			    
+{
+
+#ifndef OV511_DUMPPIX
+	int i, j, k, l, m;
+	int iOut;
+	unsigned char * pOut1;
+#define HDIV 8
+#define WDIV (256/HDIV)
+	i = iSegment / (DEFAULT_WIDTH/ WDIV);
+	j = iSegment - i * (DEFAULT_WIDTH/ WDIV);
+	iOut = (i*HDIV*DEFAULT_WIDTH + j*WDIV) * 3;
+	pOut += iOut;
+	pIn += 128;
+	for(k=0; k<4; k++) {
+	    pOut1 = pOut;
+	    for(l=0; l<8; l++) {
+	      for(m=0; m<8; m++) {
+		*pOut1++ = *pIn;
+		*pOut1++ = *pIn;
+		*pOut1++ = *pIn++;
+	      }
+	      pOut1 += (DEFAULT_WIDTH - 8) * 3;
+	    }
+	    pOut += 8 * 3;
+	}
+#else
+	/* Just dump pix data straight out for debug */
+	int i;
+	pOut += iSegment * 384;
+	for(i=0; i<384; i++) {
+	  *pOut++ = *pIn++;
+	}
+#endif
+}
 
 static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
 {
@@ -421,7 +537,7 @@
 
 		if (!n) continue;
 
-		aPackNum[i] = n ? cdata[512] : -1;
+		aPackNum[i] = n ? cdata[992] : -1;
 
 		if (st){ 
 			// Macro - must be in braces!
@@ -436,7 +552,7 @@
 		     cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
 		    (cdata[8] & 8) && (cdata[8] & 0x80)) {
 
-		    PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[512]));
+		    PDEBUG("Found Frame End!, packnum = %d\n", (int)(cdata[992]));
 		    PDEBUG("Current frame = %d\n", ov511->curframe);
 
 		    if (frame->scanstate == STATE_LINES) {
@@ -452,35 +568,47 @@
 		else if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | 
 			  cdata[4] | cdata[5] | cdata[6] | cdata[7]) == 0 &&
 			 (cdata[8] & 8)) {
-		    PDEBUG("ov511: Found Frame Start!, packnum = %d\n", (int)(cdata[512]));
+			PDEBUG("ov511: Found Frame Start!, packnum = %d\n", (int)(cdata[992]));
+			PDEBUG("ov511: Frame Header Byte = 0x%x\n", (int)(cdata[8]));
 		    frame->scanstate = STATE_LINES;
-		    frame->curpix = 0;
+			frame->segment = 0;
 		}
 
 		/* Are we in a frame? */
-		else if (frame->scanstate == STATE_LINES) {
-		  unsigned char *f = frame->data + 3 * frame->curpix;
-		  int i;
-		  if (frame->curpix <= 320 * 240 - 256) {
-		    for (i=0; i<256; i++) {
-		      *f++ = *cdata;
-		      *f++ = *cdata;
-		      *f++ = *cdata++;
-		      *f++ = *cdata;
-		      *f++ = *cdata;
-		      *f++ = *cdata++;
-		    }
-		    frame->curpix += 512;
+		if (frame->scanstate == STATE_LINES) {
+			unsigned char * pData;
+			int iPix;
+
+			/* Deal with leftover from last segment, if any */
+			if (frame->segment) {
+			  pData = ov511->scratch;
+			  iPix = - ov511->scratchlen;
+			  memmove(pData + ov511->scratchlen, cdata, iPix+384);
 		  } else {
-		    PDEBUG("Too many pixels!\n");
+			  pData = &cdata[iPix = 9];
 		  }
+
+			/* Parse the segments */
+			while(iPix <= 992 - 384 && frame->segment < 1200) {
+			  ov511_parse_data(pData, frame->data, frame->segment);
+			  frame->segment++;
+			  iPix += 384;
+			  pData = &cdata[iPix];
 		}
 
+			/* Save extra data for next time */
+			if (frame->segment < 1200) {
+			  memmove(ov511->scratch, pData, 992 - iPix);
+			  ov511->scratchlen = 992 - iPix;
+			}
+		}
 	}
 
+#if 0
 	PDEBUG("pn: %d %d %d %d %d %d %d %d %d %d\n",
 	       aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
 	       aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
+#endif
 	return totlen;
 }
 
@@ -544,24 +672,179 @@
 	ov511->cursbuf = 0;
 	ov511->scratchlen = 0;
 
-	ov511_set_packet_size(ov511, 512);
+	ov511_reg_write(ov511->dev, 0x10, 0x00);
+	ov511_reg_write(ov511->dev, 0x11, 0x01);
+	ov511_reg_write(ov511->dev, 0x12, 0x4f);
+	ov511_reg_write(ov511->dev, 0x13, 0x3d);
+	ov511_reg_write(ov511->dev, 0x14, 0x00);
+	ov511_reg_write(ov511->dev, 0x15, 0x00);
+	ov511_reg_write(ov511->dev, 0x16, 0x01); /* 01 */
+	ov511_reg_write(ov511->dev, 0x17, 0x00);
+	ov511_reg_write(ov511->dev, 0x18, 0x03);
+	ov511_reg_write(ov511->dev, 0x19, 0x00);
+	ov511_reg_write(ov511->dev, 0x1a, 0x4f);
+	ov511_reg_write(ov511->dev, 0x1b, 0x3b);
+	ov511_reg_write(ov511->dev, 0x1c, 0x00);
+	ov511_reg_write(ov511->dev, 0x1d, 0x00);
+	ov511_reg_write(ov511->dev, 0x1e, 0x01);
+	ov511_reg_write(ov511->dev, 0x1f, 0x06);
+	
+	ov511_reg_write(ov511->dev, 0x20, 0x01);
+	ov511_reg_write(ov511->dev, 0x21, 0x01);
+	ov511_reg_write(ov511->dev, 0x22, 0x01);
+	ov511_reg_write(ov511->dev, 0x23, 0x1a);
+
+	ov511_reg_write(ov511->dev, 0x30, 0x1f);
+	ov511_reg_write(ov511->dev, 0x31, 0x03);
+	ov511_reg_write(ov511->dev, 0x38, 0x00);
+	ov511_reg_write(ov511->dev, 0x39, 0x00);
+	ov511_reg_write(ov511->dev, 0x3e, 0x00);
+
+	ov511_reg_write(ov511->dev, 0x50, 0x00);
+	ov511_reg_write(ov511->dev, 0x51, 0x00);
+	ov511_reg_write(ov511->dev, 0x52, 0x01);
+	ov511_reg_write(ov511->dev, 0x53, 0x01);
+	ov511_reg_write(ov511->dev, 0x5e, 0x5a);
+	ov511_reg_write(ov511->dev, 0x5f, 0x00);
+
+	ov511_reg_write(ov511->dev, 0x70, 0x01); /* 3f */
+	ov511_reg_write(ov511->dev, 0x71, 0x01); /* 3f */
+	ov511_reg_write(ov511->dev, 0x72, 0x01);
+	ov511_reg_write(ov511->dev, 0x73, 0x01);
+	ov511_reg_write(ov511->dev, 0x74, 0x01);
+	ov511_reg_write(ov511->dev, 0x75, 0x01);
+	ov511_reg_write(ov511->dev, 0x76, 0x01);
+	ov511_reg_write(ov511->dev, 0x77, 0x01);
+	ov511_reg_write(ov511->dev, 0x78, 0x00);
+	ov511_reg_write(ov511->dev, 0x79, 0x00); /* 03 */
+
+	ov511_reg_write(ov511->dev, 0x80, 0x10);
+	ov511_reg_write(ov511->dev, 0x81, 0x21);
+	ov511_reg_write(ov511->dev, 0x82, 0x32);
+	ov511_reg_write(ov511->dev, 0x83, 0x43);
+	ov511_reg_write(ov511->dev, 0x84, 0x11);
+	ov511_reg_write(ov511->dev, 0x85, 0x21);
+	ov511_reg_write(ov511->dev, 0x86, 0x32);
+	ov511_reg_write(ov511->dev, 0x87, 0x44);
+	ov511_reg_write(ov511->dev, 0x88, 0x11);
+	ov511_reg_write(ov511->dev, 0x89, 0x22);
+	ov511_reg_write(ov511->dev, 0x8a, 0x43);
+	ov511_reg_write(ov511->dev, 0x8b, 0x44);
+	ov511_reg_write(ov511->dev, 0x8c, 0x22);
+	ov511_reg_write(ov511->dev, 0x8d, 0x32);
+	ov511_reg_write(ov511->dev, 0x8e, 0x44);
+	ov511_reg_write(ov511->dev, 0x8f, 0x44);
+	ov511_reg_write(ov511->dev, 0x90, 0x22);
+	ov511_reg_write(ov511->dev, 0x91, 0x43);
+	ov511_reg_write(ov511->dev, 0x92, 0x54);
+	ov511_reg_write(ov511->dev, 0x93, 0x55);
+	ov511_reg_write(ov511->dev, 0x94, 0x33);
+	ov511_reg_write(ov511->dev, 0x95, 0x44);
+	ov511_reg_write(ov511->dev, 0x96, 0x55);
+	ov511_reg_write(ov511->dev, 0x97, 0x55);
+	ov511_reg_write(ov511->dev, 0x98, 0x43);
+	ov511_reg_write(ov511->dev, 0x99, 0x44);
+	ov511_reg_write(ov511->dev, 0x9a, 0x55);
+	ov511_reg_write(ov511->dev, 0x9b, 0x55);
+	ov511_reg_write(ov511->dev, 0x9c, 0x44);
+	ov511_reg_write(ov511->dev, 0x9d, 0x44);
+	ov511_reg_write(ov511->dev, 0x9e, 0x55);
+	ov511_reg_write(ov511->dev, 0x9f, 0x55);
+
+	ov511_reg_write(ov511->dev, 0xa0, 0x20);
+	ov511_reg_write(ov511->dev, 0xa1, 0x32);
+	ov511_reg_write(ov511->dev, 0xa2, 0x44);
+	ov511_reg_write(ov511->dev, 0xa3, 0x44);
+	ov511_reg_write(ov511->dev, 0xa4, 0x22);
+	ov511_reg_write(ov511->dev, 0xa5, 0x42);
+	ov511_reg_write(ov511->dev, 0xa6, 0x44);
+	ov511_reg_write(ov511->dev, 0xa7, 0x44);
+	ov511_reg_write(ov511->dev, 0xa8, 0x22);
+	ov511_reg_write(ov511->dev, 0xa9, 0x43);
+	ov511_reg_write(ov511->dev, 0xaa, 0x44);
+	ov511_reg_write(ov511->dev, 0xab, 0x44);
+	ov511_reg_write(ov511->dev, 0xac, 0x43);
+	ov511_reg_write(ov511->dev, 0xad, 0x44);
+	ov511_reg_write(ov511->dev, 0xae, 0x44);
+	ov511_reg_write(ov511->dev, 0xaf, 0x44);
+	ov511_reg_write(ov511->dev, 0xb0, 0x44);
+	ov511_reg_write(ov511->dev, 0xb1, 0x44);
+	ov511_reg_write(ov511->dev, 0xb2, 0x44);
+	ov511_reg_write(ov511->dev, 0xb3, 0x44);
+	ov511_reg_write(ov511->dev, 0xb4, 0x44);
+	ov511_reg_write(ov511->dev, 0xb5, 0x44);
+	ov511_reg_write(ov511->dev, 0xb6, 0x44);
+	ov511_reg_write(ov511->dev, 0xb7, 0x44);
+	ov511_reg_write(ov511->dev, 0xb8, 0x44);
+	ov511_reg_write(ov511->dev, 0xb9, 0x44);
+	ov511_reg_write(ov511->dev, 0xba, 0x44);
+	ov511_reg_write(ov511->dev, 0xbb, 0x44);
+	ov511_reg_write(ov511->dev, 0xbc, 0x44);
+	ov511_reg_write(ov511->dev, 0xbd, 0x44);
+	ov511_reg_write(ov511->dev, 0xbe, 0x44);
+	ov511_reg_write(ov511->dev, 0xbf, 0x44);
+
+	ov511_i2c_write(ov511->dev, 0x13, 0x01); /* 01 */
+	ov511_i2c_write(ov511->dev, 0x00, 0x1E); /* 1E */
+	ov511_i2c_write(ov511->dev, 0x01, 0x80); /* 80 */
+	ov511_i2c_write(ov511->dev, 0x02, 0x80); /* 80 */
+	ov511_i2c_write(ov511->dev, 0x03, 0x86); /* 86 */
+	ov511_i2c_write(ov511->dev, 0x04, 0x80);
+	ov511_i2c_write(ov511->dev, 0x05, 0xff); /* ff */
+	ov511_i2c_write(ov511->dev, 0x06, 0x5a);
+	ov511_i2c_write(ov511->dev, 0x07, 0xd4);
+	ov511_i2c_write(ov511->dev, 0x08, 0x80);
+	ov511_i2c_write(ov511->dev, 0x09, 0x80);
+	ov511_i2c_write(ov511->dev, 0x0a, 0x80);
+	ov511_i2c_write(ov511->dev, 0x0b, 0xe0);
+	ov511_i2c_write(ov511->dev, 0x0c, 0x1f); /* 1f */
+	ov511_i2c_write(ov511->dev, 0x0d, 0x1f); /* 1f */
+	ov511_i2c_write(ov511->dev, 0x0e, 0x15); /* 15 */
+	ov511_i2c_write(ov511->dev, 0x0f, 0x03);
+	ov511_i2c_write(ov511->dev, 0x10, 0xff);
+	ov511_i2c_write(ov511->dev, 0x11, 0x01);
+	ov511_i2c_write(ov511->dev, 0x12, 0x24); /* 24 */
+	ov511_i2c_write(ov511->dev, 0x14, 0x04);
+	ov511_i2c_write(ov511->dev, 0x15, 0x01);
+	ov511_i2c_write(ov511->dev, 0x16, 0x06);
+	ov511_i2c_write(ov511->dev, 0x17, 0x38);
+	ov511_i2c_write(ov511->dev, 0x18, 0x03);
+	ov511_i2c_write(ov511->dev, 0x19, 0x05);
+	ov511_i2c_write(ov511->dev, 0x1a, 0xf4);
+	ov511_i2c_write(ov511->dev, 0x1b, 0x28);
+	ov511_i2c_write(ov511->dev, 0x1c, 0x7f);
+	ov511_i2c_write(ov511->dev, 0x1d, 0xa2);
+	ov511_i2c_write(ov511->dev, 0x1e, 0xc4);
+	ov511_i2c_write(ov511->dev, 0x1f, 0x04);
+	ov511_i2c_write(ov511->dev, 0x20, 0x1c);
+	ov511_i2c_write(ov511->dev, 0x21, 0x80);
+	ov511_i2c_write(ov511->dev, 0x22, 0x80);
+	ov511_i2c_write(ov511->dev, 0x23, 0x2a);
+	ov511_i2c_write(ov511->dev, 0x24, 0x10); /* 10 */
+	ov511_i2c_write(ov511->dev, 0x25, 0x8a); /* 8a */
+	ov511_i2c_write(ov511->dev, 0x26, 0x70);
+	ov511_i2c_write(ov511->dev, 0x27, 0xc2);
+	ov511_i2c_write(ov511->dev, 0x28, 0x24);
+	ov511_i2c_write(ov511->dev, 0x29, 0x11);
+	ov511_i2c_write(ov511->dev, 0x2a, 0x04);
+	ov511_i2c_write(ov511->dev, 0x2b, 0xac);
+	ov511_i2c_write(ov511->dev, 0x2c, 0xfe);
+	ov511_i2c_write(ov511->dev, 0x2d, 0x93);
+	ov511_i2c_write(ov511->dev, 0x2e, 0x80);
+	ov511_i2c_write(ov511->dev, 0x2f, 0xb0);
+	ov511_i2c_write(ov511->dev, 0x30, 0x71);
+	ov511_i2c_write(ov511->dev, 0x31, 0x90);
+	ov511_i2c_write(ov511->dev, 0x32, 0x22);
+	ov511_i2c_write(ov511->dev, 0x33, 0x20);
+	ov511_i2c_write(ov511->dev, 0x34, 0x8b);
+	ov511_i2c_write(ov511->dev, 0x35, 0x9e);
+	ov511_i2c_write(ov511->dev, 0x36, 0x7f);
+	ov511_i2c_write(ov511->dev, 0x37, 0x7f);
+	ov511_i2c_write(ov511->dev, 0x38, 0x81);
 	
-#define OV511_COLOR_BAR_TEST
-#ifdef OV511_COLOR_BAR_TEST
-	{
-	  int rc;
-	  rc = ov511_i2c_read(ov511->dev, 0x12);
-	  rc = ov511_i2c_write(ov511->dev, 0x12, 0x3f);
-	  rc = ov511_i2c_read(ov511->dev, 0x12);
-	  rc = ov511_i2c_read(ov511->dev, 0x13);
-	  rc = ov511_i2c_write(ov511->dev, 0x14, 0x4);
-	  rc = ov511_i2c_read(ov511->dev, 0x14);
-	  rc = ov511_i2c_write(ov511->dev, 0x28, 0x60);
-	  rc = ov511_i2c_read(ov511->dev, 0x28);
-	  ov511_reg_write(ov511->dev, OV511_REG_CAMERA_DATA_INPUT_SELECT,
-			      0);
-	}
-#endif
+	ov511_dump_i2c_regs(ov511->dev);
+
+	ov511_set_packet_size(ov511, 993);
 
 	/* We double buffer the Iso lists */
 	urb = usb_alloc_urb(FRAMES_PER_DESC);
@@ -1265,13 +1548,25 @@
 	if (rc < 0) {
 		printk("ov511: Unable to read camera bridge registers\n");
 		return NULL;
-	} else if (rc == 3) {  /* D-Link DSB-C300 */
+	}
+	
+	switch(ov511->customid = rc) {
+	case 0: /* This also means that no custom ID was set */
+		printk("ov511: Camera is probably a MediaForte MV300\n");
+		break;
+	case 3:
 		printk("ov511: Camera is a D-Link DSB-C300\n");
-		ov511->customid = 3;
-	} else if (rc == 21) { /* Creative Labs WebCam 3 */
+		break;
+	case 21:
 		printk("ov511: Camera is a Creative Labs WebCam 3\n");
-		ov511->customid = 21;		
-	} else {
+		break;
+	case 100:
+		printk("ov511: Camera is a Lifeview RoboCam\n");
+		break;
+	case 102:
+		printk("ov511: Camera is a AverMedia InterCam Elite\n");
+		break;
+	default:
 		printk("ov511: Specific camera type (%d) not recognized\n", rc);
 		printk("ov511: Please contact mmcclelland@delphi.com to request\n");
 		printk("ov511: support for your camera.\n");
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h
--- v2.3.38/linux/drivers/usb/ov511.h	Thu Jan  6 12:57:48 2000
+++ linux/drivers/usb/ov511.h	Mon Jan 10 11:37:53 2000
@@ -106,10 +106,10 @@
 
 #define STREAM_BUF_SIZE	(PAGE_SIZE * 4)
 
-#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
+#define SCRATCH_BUF_SIZE 384
 
 #define FRAMES_PER_DESC		10  /* FIXME - What should this be? */
-#define FRAME_SIZE_PER_DESC	512	/* FIXME - Shouldn't be hardcoded */
+#define FRAME_SIZE_PER_DESC	993	/* FIXME - Shouldn't be hardcoded */
 
 // FIXME - should this be 0x81 (endpoint address) or 0x01 (endpoint number)?
 #define OV511_ENDPOINT_ADDRESS 0x81 /* Address of isoc endpoint */
@@ -166,6 +166,7 @@
 
 	int curline;		/* Line of frame we're working on */
 	int curpix;
+	int segment;		/* Segment from the incoming data */
 
 	long scanlength;	/* uncompressed, raw data length of frame */
 	long bytes_read;	/* amount of scanlength that has been read from *data */
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c
--- v2.3.38/linux/drivers/usb/proc_usb.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/proc_usb.c	Mon Jan 10 16:05:19 2000
@@ -121,9 +121,6 @@
  * However, these will come from functions that return ptrs to each of them.
  */
 
-extern struct list_head *usb_driver_get_list (void);
-extern struct list_head *usb_bus_get_list (void);
-
 extern struct proc_dir_entry *proc_bus;
 
 static struct proc_dir_entry *usbdir = NULL, *driversdir = NULL;
@@ -293,49 +290,35 @@
 /*
  * Dump the different strings that this device holds.
  */
-static char *usb_dump_device_strings (char *start, char *end, const struct usb_device *dev)
+static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
 {
+	char *buf;
+
 	if (start > end)
 		return start;
-
+	buf = kmalloc(256, GFP_KERNEL);
+	if (!buf)
+		return start;
 	if (dev->descriptor.iManufacturer) {
-		char * string = usb_string ((struct usb_device *)dev, 
-					dev->descriptor.iManufacturer);
-		if (string) {
-			start += sprintf (start, format_string_manufacturer,
-					string
-					);
-		if (start > end)
-			return start;
-								
-		}
-	}
-
+		if (usb_string(dev, dev->descriptor.iManufacturer, buf, 256) > 0)
+			start += sprintf(start, format_string_manufacturer, buf);
+	}				
+	if (start > end)
+		goto out;
 	if (dev->descriptor.iProduct) {
-		char * string = usb_string ((struct usb_device *)dev, 
-					dev->descriptor.iProduct);
-		if (string) {
-			start += sprintf (start, format_string_product,
-					string
-					);
-		if (start > end)
-			return start;
-
-		}
+		if (usb_string(dev, dev->descriptor.iProduct, buf, 256) > 0)
+			start += sprintf(start, format_string_product, buf);
 	}
-
+	if (start > end)
+		goto out;
 #ifdef ALLOW_SERIAL_NUMBER
 	if (dev->descriptor.iSerialNumber) {
-		char * string = usb_string ((struct usb_device *)dev, 
-					dev->descriptor.iSerialNumber);
-		if (string) {
-			start += sprintf (start, format_string_serialnumber,
-					string
-					);
-		}
+		if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 256) > 0)
+			start += sprintf(start, format_string_serialnumber, buf);
 	}
 #endif
-
+ out:
+	kfree(buf);
 	return start;
 }
 
@@ -432,7 +415,7 @@
 
 static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 {
-	struct list_head *usb_bus_list, *buslist;
+	struct list_head *buslist;
 	struct usb_bus *bus;
 	char *page, *end;
 	ssize_t ret = 0;
@@ -447,9 +430,8 @@
 	if (!(page = (char*) __get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
 	pos = *ppos;
-	usb_bus_list = usb_bus_get_list();
 	/* enumerate busses */
-	for (buslist = usb_bus_list->next; buslist != usb_bus_list; buslist = buslist->next) {
+	for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
 		bus = list_entry(buslist, struct usb_bus, bus_list);
 		end = usb_device_dump(page, page + (PAGE_SIZE - 100), bus->root_hub, bus, 0, 0, 0);
 		len = end - page;
@@ -525,8 +507,7 @@
  */
 static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
 {
-	struct list_head *usb_driver_list = usb_driver_get_list();
-	struct list_head *tmp = usb_driver_list->next;
+	struct list_head *tmp = usb_driver_list.next;
 	char *page, *start, *end;
 	ssize_t ret = 0;
 	unsigned int pos, len;
@@ -542,7 +523,7 @@
 	start = page;
 	end = page + (PAGE_SIZE - 100);
 	pos = *ppos;
-	for (; tmp != usb_driver_list; tmp = tmp->next) {
+	for (; tmp != &usb_driver_list; tmp = tmp->next) {
 		struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
 		start += sprintf (start, "%s\n", driver->name);
 		if (start > end) {
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.3.38/linux/drivers/usb/scanner.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/scanner.c	Mon Jan 10 16:05:19 2000
@@ -410,9 +410,12 @@
 		hps->oep = endpoint[1].bEndpointAddress;
 	}
 
-	ident = usb_string(dev, dev->descriptor.iProduct); /* usb_string allocates memory using kmalloc() so kfree() needs to be called afterwards when the pointer is no longer needed. */
-	info("USB Scanner (%s) found at address %d", ident, dev->devnum);
-	kfree(ident);
+	ident = kmalloc(256, GFP_KERNEL);
+	if (ident) {
+		usb_string(dev, dev->descriptor.iProduct, ident, 256);
+		info("USB Scanner (%s) found at address %d", ident, dev->devnum);
+		kfree(ident);
+	}
 
 	dbg("probe_scanner: using bulk endpoints - In: %x  Out: %x", hps->iep, hps->oep);
 
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.38/linux/drivers/usb/usb-core.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/usb/usb-core.c	Mon Jan 10 11:37:53 2000
@@ -38,7 +38,7 @@
 int usb_dc2xx_init(void);
 int usb_scanner_init(void);
 int usb_printer_init(void);
-int usb_scsi_init(void);
+int usb_stor_init(void);
 int usb_serial_init(void);
 int dabusb_init(void);
 int hid_init(void);
@@ -65,7 +65,8 @@
 #ifdef CONFIG_USB_PROC
 	proc_usb_cleanup ();
 #endif
-	usb_hub_cleanup();	
+        usbdevfs_cleanup();
+	usb_hub_cleanup();
 
 }
 
@@ -82,6 +83,7 @@
 #ifdef CONFIG_USB_PROC
 	proc_usb_init();
 #endif
+        usbdevfs_init();
 	usb_hub_init();
 
 #ifndef CONFIG_USB_MODULE
@@ -110,7 +112,7 @@
 	usb_dc2xx_init();
 #endif
 #ifdef CONFIG_USB_SCSI
-	usb_scsi_init();
+	usb_stor_init();
 #endif
 #ifdef CONFIG_USB_DABUSB
 	dabusb_init();
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/usb-debug.c linux/drivers/usb/usb-debug.c
--- v2.3.38/linux/drivers/usb/usb-debug.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/usb-debug.c	Mon Jan 10 16:05:19 2000
@@ -6,6 +6,7 @@
  */
 #include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/slab.h>
 
 #define DEBUG
 
@@ -175,9 +176,12 @@
 
 void usb_show_string(struct usb_device *dev, char *id, int index)
 {
-	char *p = usb_string(dev, index);
+	char *buf;
 
-	if (p != 0)
-		printk(KERN_INFO "%s: %s\n", id, p);
+	if (!(buf = kmalloc(256, GFP_KERNEL)))
+		return;
+	if (usb_string(dev, index, buf, 256) > 0)
+		printk(KERN_INFO "%s: %s\n", id, buf);
+	kfree(buf);
 }
 
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.38/linux/drivers/usb/usb.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/usb.c	Mon Jan 10 16:05:19 2000
@@ -39,8 +39,8 @@
 /*
  * We have a per-interface "registered driver" list.
  */
-static LIST_HEAD(usb_driver_list);
-static LIST_HEAD(usb_bus_list);
+LIST_HEAD(usb_driver_list);
+LIST_HEAD(usb_bus_list);
 
 static struct usb_busmap busmap;
 
@@ -240,6 +240,7 @@
 	bus->bandwidth_isoc_reqs = 0;
 
 	INIT_LIST_HEAD(&bus->bus_list);
+        INIT_LIST_HEAD(&bus->inodes);
 
 	return bus;
 }
@@ -268,6 +269,8 @@
 	/* Add it to the list of buses */
 	list_add(&bus->bus_list, &usb_bus_list);
 
+	usbdevfs_add_bus(bus);
+
 	info("new USB bus registered, assigned bus number %d", bus->busnum);
 }
 
@@ -284,6 +287,8 @@
 
 	proc_usb_remove_bus(bus);
 
+        usbdevfs_remove_bus(bus);
+
 	clear_bit(bus->busnum, busmap.busmap);
 }
 
@@ -443,6 +448,8 @@
 	dev->bus = bus;
 	dev->parent = parent;
 	atomic_set(&dev->refcnt, 1);
+        INIT_LIST_HEAD(&dev->inodes);
+        INIT_LIST_HEAD(&dev->filelist);
 
 	dev->bus->op->allocate(dev);
 
@@ -1154,11 +1161,6 @@
 		kfree(cf->interface);
 	}
 	kfree(dev->config);
-
-	if (dev->string) {
-		kfree(dev->string);
-		dev->string = 0;
- 	}
 }
 			
 void usb_init_root_hub(struct usb_device *dev)
@@ -1230,6 +1232,7 @@
 
 	/* remove /proc/bus/usb entry */
 	proc_usb_remove_device(dev);
+        usbdevfs_remove_device(dev);
 
 	/* Free up the device itself, including its device number */
 	if (dev->devnum > 0)
@@ -1491,6 +1494,11 @@
 		return -1;
 	}
 
+	if (dev->descriptor.bNumConfigurations < 1) {
+		warn("not enough configurations");
+		return -1;
+	}
+
 	dev->config = (struct usb_config_descriptor *)
 		kmalloc(dev->descriptor.bNumConfigurations *
 		sizeof(struct usb_config_descriptor), GFP_KERNEL);
@@ -1547,54 +1555,45 @@
 	return result;
 }
 
-char *usb_string(struct usb_device *dev, int index)
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
 {
-	int i, len, ret;
-	char *ptr;
-	union {
-		unsigned char buffer[256];
-		struct usb_string_descriptor desc;
-	} u;
-
-	if (index <= 0)
-		return 0;
-	if (dev->string)
-		kfree (dev->string);
-
-	if (dev->string_langid == 0) {
-		/* read string descriptor 0 */
-		ret = usb_get_string(dev, 0, 0, u.buffer, 4);
-		if (ret >= 0 && u.desc.bLength >= 4)
-			dev->string_langid = le16_to_cpup(&u.desc.wData[0]);
-		else
-			err("error getting string");
-		dev->string_langid |= 0x10000;	/* so it's non-zero */
-	}
-
-	if (usb_get_string(dev, dev->string_langid, index, u.buffer, 4) < 0 ||
-	    ((ret = usb_get_string(dev, dev->string_langid, index, u.buffer,
-			      u.desc.bLength)) < 0)) {
-		err("error retrieving string");
-		return NULL;
-	}
+	unsigned char *tbuf;
+	int err;
+	unsigned int u, idx;
 
-	if (ret > 0) ret /= 2;		/* going from 16-bit chars to 8-bit */
-	len = u.desc.bLength / 2;	/* includes terminating null */
-					/* after removing bLength & bDescType */
-	if (ret < len) len = ret;	/* use min of (ret, len) */
-
-	ptr = kmalloc(len, GFP_KERNEL);
-	if (!ptr) {
-		err("couldn't allocate memory for string");
-		return NULL;
+	if (size <= 0 || !buf)
+		return -EINVAL;
+	buf[0] = 0;
+	tbuf = kmalloc(256, GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+	/*
+	 * is this two step process necessary? can't we just
+	 * ask for a maximum length string and then take the length
+	 * that was returned?
+	 */
+	err = usb_get_string(dev, dev->string_langid, index, tbuf, 4);
+	if (err < 0)
+		goto errout;
+	err = usb_get_string(dev, dev->string_langid, index, tbuf, tbuf[0]);
+	if (err < 0)
+		goto errout;
+	size--;
+	for (idx = 0, u = 2; u < tbuf[0]; u += 2) {
+		if (idx >= size)
+			break;
+		if (tbuf[u+1]) {
+			buf[idx++] = '?';  /* non ASCII character */
+			continue;
+		}
+		buf[idx++] = tbuf[u];
 	}
+	buf[idx] = 0;
+	err = idx;
 
-	for (i = 0; i < len - 1; ++i)
-		ptr[i] = le16_to_cpup(&u.desc.wData[i]);
-	ptr[i] = 0;
-
-	dev->string = ptr;
-	return ptr;
+ errout:
+	kfree(tbuf);
+	return err;
 }
 
 /*
@@ -1606,10 +1605,10 @@
  */
 int usb_new_device(struct usb_device *dev)
 {
+	unsigned char *buf;
 	int addr, err;
 
-	info("USB new device connect, assigned device number %d",
-		dev->devnum);
+	info("USB new device connect, assigned device number %d", dev->devnum);
  
 	dev->maxpacketsize = 0;		/* Default to 8 byte max packet size */
 	dev->epmaxpacketin [0] = 8;
@@ -1657,8 +1656,7 @@
 		return 1;
 	}
 
-	err=usb_get_configuration(dev);
-	
+	err = usb_get_configuration(dev);
 	if (err < 0) {
 		err("unable to get configuration (error=%d)", err);
 		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
@@ -1674,6 +1672,21 @@
 		err("failed to set default configuration");
 		return -1;
 	}
+	/* get langid for strings */
+	buf = kmalloc(256, GFP_KERNEL);
+	if (!buf) {
+		err("out of memory\n");
+	} else {
+		err = usb_get_string(dev, 0, 0, buf, 4);
+		if (err < 0) {
+			err("error getting string descriptor 0 (error=%d)\n", err);
+		} else if (buf[0] < 4) {
+			err("string descriptpr 0 too short\n");
+		} else
+			dev->string_langid = buf[2] | (buf[3]<< 8);
+		kfree(buf);
+		info("USB device number %d default language ID 0x%x", dev->devnum, dev->string_langid);
+	}
 
 	usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
 	usb_show_string(dev, "Product", dev->descriptor.iProduct);
@@ -1681,6 +1694,7 @@
 
 	/* now that the basic setup is over, add a /proc/bus/usb entry */
 	proc_usb_add_device(dev);
+        usbdevfs_add_device(dev);
 
 	/* find drivers willing to handle this device */
 	usb_find_drivers(dev);
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.38/linux/drivers/usb/usb.h	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/usb.h	Mon Jan 10 16:05:19 2000
@@ -550,6 +550,8 @@
 
 	/* procfs entry */
 	struct proc_dir_entry *proc_entry;
+        /* usbdevfs inode list */
+        struct list_head inodes;
 };
 
 #define USB_MAXCHILDREN (8)	/* This is arbitrary */
@@ -574,13 +576,15 @@
 	struct usb_device_descriptor descriptor;/* Descriptor */
 	struct usb_config_descriptor *config;	/* All of the configs */
 
-	char *string;			/* pointer to the last string read from the device */
 	int string_langid;		/* language ID for strings */
   
 	void *hcpriv;			/* Host Controller private data */
 	
 	/* procfs entry */
 	struct proc_dir_entry *proc_entry;
+        /* usbdevfs inode list */
+        struct list_head inodes;
+        struct list_head filelist;
 
 	/*
 	 * Child devices - these can be either new devices
@@ -746,7 +750,7 @@
 	unsigned char id, unsigned char index, void *buf, int size);
 int usb_set_report(struct usb_device *dev, unsigned char type,
 	unsigned char id, unsigned char index, void *buf, int size);
-char *usb_string(struct usb_device *dev, int index);
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
 int usb_clear_halt(struct usb_device *dev, int endp);
 
 #define usb_get_extra_descriptor(ifpoint,type,ptr)\
@@ -786,7 +790,7 @@
 #ifdef DEBUG
 #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n", ## arg)
 #else
-#define dbg(format, arg...)
+#define dbg(format, arg...) do {} while (0)
 #endif
 #define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n", ## arg)
 #define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n", ## arg)
@@ -794,6 +798,13 @@
 
 
 /*
+ * bus and driver list
+ */
+
+extern struct list_head usb_driver_list;
+extern struct list_head usb_bus_list;
+
+/*
  * procfs stuff
  */
 
@@ -808,6 +819,36 @@
 extern inline void proc_usb_add_device(struct usb_device *dev) {}
 extern inline void proc_usb_remove_device(struct usb_device *dev) {}
 #endif
+
+/*
+ * USB device fs stuff
+ */
+
+#ifdef CONFIG_USB_DEVICEFS
+
+/*
+ * these are expected to be called from the USB core/hub thread
+ * with the kernel lock held
+ */
+extern void usbdevfs_add_bus(struct usb_bus *bus);
+extern void usbdevfs_remove_bus(struct usb_bus *bus);
+extern void usbdevfs_add_device(struct usb_device *dev);
+extern void usbdevfs_remove_device(struct usb_device *dev);
+
+extern int usbdevfs_init(void);
+extern void usbdevfs_cleanup(void);
+
+#else /* CONFIG_USB_DEVICEFS */
+
+extern inline void usbdevfs_add_bus(struct usb_bus *bus) {}
+extern inline void usbdevfs_remove_bus(struct usb_bus *bus) {}
+extern inline void usbdevfs_add_device(struct usb_device *dev) {}
+extern inline void usbdevfs_remove_device(struct usb_device *dev) {}
+
+extern inline int usbdevfs_init(void) { return 0; }
+extern inline void usbdevfs_cleanup(void) { }
+
+#endif /* CONFIG_USB_DEVICEFS */
 
 #endif  /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.38/linux/drivers/usb/usb_scsi.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/usb/usb_scsi.c	Mon Jan 10 16:05:19 2000
@@ -770,24 +770,24 @@
 	SPRINTF ("Host scsi%d: usb-scsi\n", hostno);
 
 	/* print product and vendor strings */
-	if (!us->pusb_dev) {
+	tmp_ptr = kmalloc(256, GFP_KERNEL);
+	if (!us->pusb_dev || !tmp_ptr) {
 		SPRINTF("Vendor: Unknown Vendor\n");
 		SPRINTF("Product: Unknown Product\n");
 	} else {
 		SPRINTF("Vendor: ");
-		tmp_ptr = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer);
-		if (!tmp_ptr)
-			SPRINTF("Unknown Vendor\n");
-		else
+		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0)
 			SPRINTF("%s\n", tmp_ptr);
+		else
+			SPRINTF("Unknown Vendor\n");
     
 		SPRINTF("Product: ");
-		tmp_ptr = usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct);
-		if (!tmp_ptr)
-			SPRINTF("Unknown Vendor\n");
-		else
+		if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0)
 			SPRINTF("%s\n", tmp_ptr);
+		else
+			SPRINTF("Unknown Vendor\n");
 	}
+	kfree(tmp_ptr);
 
 	SPRINTF("Protocol: ");
 	switch (us->protocol) {
@@ -1196,9 +1196,9 @@
 {
 	struct usb_interface_descriptor *interface;
 	int i;
-	char *mf;		     /* manufacturer */
-	char *prod;		     /* product */
-	char *serial;		     /* serial number */
+	char mf[32];		     /* manufacturer */
+	char prod[32];		     /* product */
+	char serial[32];	     /* serial number */
 	struct us_data *ss = NULL;
 	unsigned int flags = 0;
 	GUID(guid);		     /* Global Unique Identifier */
@@ -1211,9 +1211,9 @@
 
 	/* clear the GUID and fetch the strings */
 	GUID_CLEAR(guid);
-	mf = usb_string(dev, dev->descriptor.iManufacturer);
-	prod = usb_string(dev, dev->descriptor.iProduct);
-	serial = usb_string(dev, dev->descriptor.iSerialNumber);
+	usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf));
+	usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod));
+	usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial));
 
 	/* let's examine the device now */
 
@@ -1234,12 +1234,11 @@
 	US_DEBUGP("USB Mass Storage device detected\n");
 
 	/* Create a GUID for this device */
-	if (dev->descriptor.iSerialNumber &&
-	    usb_string(dev, dev->descriptor.iSerialNumber) ) {
+	if (dev->descriptor.iSerialNumber && serial[0]) {
 		/* If we have a serial number, and it's a non-NULL string */
 		make_guid(guid, dev->descriptor.idVendor, 
 			  dev->descriptor.idProduct,
-			  usb_string(dev, dev->descriptor.iSerialNumber));
+			  serial);
 	} else {
 		/* We don't have a serial number, so we use 0 */
 		make_guid(guid, dev->descriptor.idVendor, 
diff -u --recursive --new-file v2.3.38/linux/drivers/usb/usbdevice_fs.h linux/drivers/usb/usbdevice_fs.h
--- v2.3.38/linux/drivers/usb/usbdevice_fs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usbdevice_fs.h	Mon Jan 10 11:32:48 2000
@@ -0,0 +1,168 @@
+/*****************************************************************************/
+
+/*
+ *	usbdevice_fs.h  --  USB device file system.
+ *
+ *	Copyright (C) 2000
+ *          Thomas Sailer (sailer@ife.ee.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
+ *	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.
+ *
+ *  History:
+ *   0.1  04.01.2000  Created
+ *
+ *  $Id: ezusb.c,v 1.22 1999/12/03 15:06:28 tom Exp $
+ */
+
+/*****************************************************************************/
+
+#ifndef _LINUX_USBDEVICE_FS_H
+#define _LINUX_USBDEVICE_FS_H
+
+/* --------------------------------------------------------------------- */
+
+#define USBDEVICE_SUPER_MAGIC 0x9fa2
+
+/* usbdevfs ioctl codes */
+
+struct usbdevfs_ctrltransfer {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+ 	void *data;
+};
+
+struct usbdevfs_bulktransfer {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	void *data;
+};
+
+struct usbdevfs_setinterface {
+	unsigned int interface;
+	unsigned int altsetting;
+};
+
+struct usbdevfs_disconnectsignal {
+	unsigned int signr;
+	void *context;
+};
+
+#define USBDEVFS_URB_DISABLE_SPD           1
+#define USBDEVFS_URB_ISO_ASAP              2
+
+#define USBDEVFS_URB_TYPE_ISO		   0
+#define USBDEVFS_URB_TYPE_INTERRUPT	   1
+#define USBDEVFS_URB_TYPE_CONTROL	   2
+#define USBDEVFS_URB_TYPE_BULK		   3
+
+struct usbdevfs_iso_packet_desc {
+	unsigned int length;
+	unsigned int actual_length;
+	unsigned int status;
+};
+
+struct usbdevfs_urb {
+	unsigned char type;
+	unsigned char endpoint;
+	int status;
+	unsigned int flags;
+	void *buffer;
+	int buffer_length;
+	int actual_length;
+	int start_frame;
+	int number_of_packets;
+	int error_count;
+	unsigned int signr;  /* signal to be sent on error, -1 if none should be sent */
+	void *usercontext;
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+#define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
+#define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
+#define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
+#define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
+#define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
+#define USBDEVFS_DISCARDURB        _IO('U', 11)
+#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
+#define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
+#define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
+#define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
+#define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
+
+/* --------------------------------------------------------------------- */
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <asm/semaphore.h>
+
+/*
+ * inode number macros
+ */
+#define ITYPE(x)   ((x)&(0xf<<28))
+#define ISPECIAL   (0<<28)
+#define IBUS       (1<<28)
+#define IDEVICE    (2<<28)
+#define IBUSNR(x)  (((x)>>8)&0xff)
+#define IDEVNR(x)  ((x)&0xff)
+
+#define IROOT      1
+
+/*
+ * sigh. rwsemaphores do not (yet) work from modules
+ */
+
+#define rw_semaphore semaphore
+#define init_rwsem init_MUTEX
+#define down_read down
+#define down_write down
+#define up_read up
+#define up_write up
+
+
+struct dev_state {
+	struct list_head list;      /* state list */
+	struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */ 
+	struct usb_device *dev;
+	struct file *file;
+	spinlock_t lock;            /* protects the async urb lists */
+	struct list_head async_pending;
+	struct list_head async_completed;
+	wait_queue_head_t wait;     /* wake up if a request completed */
+	unsigned int discsignr;
+	struct task_struct *disctask;
+	void *disccontext;
+	unsigned long ifclaimed;
+};
+
+/* internal methods & data */
+extern struct usb_driver usbdevfs_driver;
+extern struct file_operations usbdevfs_drivers_fops;
+extern struct file_operations usbdevfs_devices_fops;
+extern struct inode_operations usbdevfs_device_inode_operations;
+extern void usbdevfs_conn_disc_event(void);
+
+
+#endif /* __KERNEL__ */
+
+/* --------------------------------------------------------------------- */
+#endif /* _LINUX_USBDEVICE_FS_H */
diff -u --recursive --new-file v2.3.38/linux/drivers/video/aty128.h linux/drivers/video/aty128.h
--- v2.3.38/linux/drivers/video/aty128.h	Fri Oct 22 13:21:51 1999
+++ linux/drivers/video/aty128.h	Mon Jan 10 12:19:09 2000
@@ -3,65 +3,33 @@
  *  Register definitions for ATI Rage128 boards
  *
  *  Anthony Tong <atong@uiuc.edu>, 1999
+ *  Brad Douglas <brad@neruo.com>, 2000
  */
 
 #ifndef REG_RAGE128_H
 #define REG_RAGE128_H
 
-#define MM_INDEX				0x0000
-#define MM_DATA					0x0004
 #define CLOCK_CNTL_INDEX			0x0008
 #define CLOCK_CNTL_DATA				0x000c
 #define BIOS_0_SCRATCH				0x0010
-#define BIOS_1_SCRATCH				0x0014
-#define BIOS_2_SCRATCH				0x0018
-#define BIOS_3_SCRATCH				0x001c
 #define BUS_CNTL				0x0030
-#define BUS_CNTL1				0x0034
-#define MEM_VGA_WP_SEL				0x0038
-#define MEM_VGA_RP_SEL				0x003c
 #define GEN_INT_CNTL				0x0040
-#define GEN_INT_STATUS				0x0044
 #define CRTC_GEN_CNTL				0x0050
 #define CRTC_EXT_CNTL				0x0054
 #define DAC_CNTL				0x0058
-#define CRTC_STATUS				0x005c
-#define GPIO_MONID				0x0068
 #define I2C_CNTL_1				0x0094
 #define PALETTE_INDEX				0x00b0
 #define PALETTE_DATA				0x00b4
 #define CONFIG_CNTL				0x00e0
-#define CONFIG_XSTRAP				0x00e4
-#define CONFIG_BONDS				0x00e8
 #define GEN_RESET_CNTL				0x00f0
-#define GEN_STATUS				0x00f4
 #define CONFIG_MEMSIZE				0x00f8
-#define CONFIG_APER_0_BASE			0x0100
-#define CONFIG_APER_1_BASE			0x0104
-#define CONFIG_APER_SIZE			0x0108
-#define CONFIG_REG_1_BASE			0x010c
-#define CONFIG_REG_APER_SIZE			0x0110
-#define CONFIG_MEMSIZE_EMBEDDED			0x0114
-#define TEST_DEBUG_CNTL				0x0120
-#define TEST_DEBUG_MUX				0x0124
-#define HW_DEBUG				0x0128
-#define TEST_DEBUG_OUT				0x012c
-#define HOST_PATH_CNTL				0x0130
-#define SW_SEMAPHORE				0x013c
 #define MEM_CNTL				0x0140
-#define EXT_MEM_CNTL				0x0144
-#define MEM_ADDR_CONFIG				0x0148
-#define MEM_INTF_CNTL				0x014c
-#define MEM_STR_CNTL				0x0150
-#define MEM_INIT_LAT_TIMER			0x0154
-#define MEM_SDRAM_MODE_REG			0x0158
 #define AGP_BASE				0x0170
 #define AGP_CNTL				0x0174
 #define AGP_APER_OFFSET				0x0178
 #define PCI_GART_PAGE				0x017c
 #define PC_NGUI_MODE				0x0180
 #define PC_NGUI_CTLSTAT				0x0184
-#define VIDEOMUX_CNTL				0x0190
 #define MPP_TB_CONFIG				0x01C0
 #define MPP_GP_CONFIG				0x01C8
 #define VIPH_CONTROL				0x01D0
@@ -69,72 +37,17 @@
 #define CRTC_H_SYNC_STRT_WID			0x0204
 #define CRTC_V_TOTAL_DISP			0x0208
 #define CRTC_V_SYNC_STRT_WID			0x020c
-#define CRTC_VLINE_CRNT_VLINE			0x0210
-#define CRTC_CRNT_FRAME				0x0214
-#define CRTC_GUI_TRIG_VLINE			0x0218
-#define CRTC_DEBUG				0x021c
 #define CRTC_OFFSET				0x0224
 #define CRTC_OFFSET_CNTL			0x0228
 #define CRTC_PITCH				0x022c
 #define OVR_CLR					0x0230
 #define OVR_WID_LEFT_RIGHT			0x0234
 #define OVR_WID_TOP_BOTTOM			0x0238
-#define SNAPSHOT_VH_COUNTS			0x0240
-#define SNAPSHOT_F_COUNT			0x0244
-#define N_VIF_COUNT				0x0248
-#define SNAPSHOT_VIF_COUNT			0x024c
-#define CUR_OFFSET				0x0260
-#define CUR_HORZ_VERT_POSN			0x0264
-#define CUR_HORZ_VERT_OFF			0x0268
-#define CUR_CLR0				0x026c
-#define CUR_CLR1				0x0270
-#define DAC_CRC_SIG				0x02cc
 #define DDA_CONFIG				0x02e0
 #define DDA_ON_OFF				0x02e4
 #define VGA_DDA_CONFIG				0x02e8
 #define VGA_DDA_ON_OFF				0x02ec
-#define OV0_Y_X_START				0x0400
-#define OV0_Y_X_END				0x0404
-#define OV0_EXCLUSIVE_HORZ			0x0408
-#define OV0_EXCLUSIVE_VERT			0x040c
-#define OV0_REG_LOAD_CNTL			0x0410
 #define OV0_SCALE_CNTL				0x0420
-#define OV0_V_INC				0x0424
-#define OV0_P1_V_ACCUM_INIT			0x0428
-#define OV0_P23_V_ACCUM_INIT			0x042c
-#define OV0_P1_BLANK_LINES_AT_TOP		0x0430
-#define OV0_P23_BLANK_LINES_AT_TOP		0x0434
-#define OV0_VID_BUF0_BASE_ADRS			0x0440
-#define OV0_VID_BUF1_BASE_ADRS			0x0444
-#define OV0_VID_BUF2_BASE_ADRS			0x0448
-#define OV0_VID_BUF3_BASE_ADRS			0x044c
-#define OV0_VID_BUF4_BASE_ADRS			0x0450
-#define OV0_VID_BUF5_BASE_ADRS			0x0454
-#define OV0_VID_BUF_PITCH0_VALUE		0x0460
-#define OV0_VID_BUF_PITCH1_VALUE		0x0464
-#define OV0_OCTWORDS_PER_LINE_M1		0x046c
-#define OV0_AUTO_FLIP_CNTRL			0x0470
-#define OV0_DEINTERLACE_PATTERN			0x0474
-#define OV0_H_INC				0x0480
-#define OV0_STEP_BY				0x0484
-#define OV0_P1_H_ACCUM_INIT			0x0488
-#define OV0_P23_H_ACCUM_INIT			0x048c
-#define OV0_P1_X_START_END			0x0494
-#define OV0_P2_X_START_END			0x0498
-#define OV0_P3_X_START_END			0x049c
-#define OV0_FILTER_CNTL				0x04a0
-#define OV0_FOUR_TAP_COEF_0			0x04b0
-#define OV0_FOUR_TAP_COEF_1			0x04b4
-#define OV0_FOUR_TAP_COEF_2			0x04b8
-#define OV0_FOUR_TAP_COEF_3			0x04bc
-#define OV0_FOUR_TAP_COEF_4			0x04c0
-#define OV0_COLOR_CNTL				0x04e0
-#define OV0_VIDEO_KEY_CLR			0x04e4
-#define OV0_VIDEO_KEY_MASK			0x04e8
-#define OV0_GRAPHICS_KEY_CLR			0x04ec
-#define OV0_GRAPHICS_KEY_MASK			0x04f0
-#define OV0_KEY_CNTL				0x04f4
-#define OV0_TEST				0x04f8
 #define SUBPIC_CNTL				0x0540
 #define PM4_BUFFER_OFFSET			0x0700
 #define PM4_BUFFER_CNTL				0x0704
@@ -152,9 +65,7 @@
 #define PM4_IW_INDOFF				0x0738
 #define PM4_IW_INDSIZE				0x073c
 #define PM4_FPU_FPX0				0x0740
-#define CRC_CMDFIFO_ADDR			0x0740
 #define PM4_FPU_FPY0				0x0744
-#define CRC_CMDFIFO_DOUT			0x0744
 #define PM4_FPU_FPX1				0x0748
 #define PM4_FPU_FPY1				0x074c
 #define PM4_FPU_FPX2				0x0750
@@ -189,77 +100,8 @@
 #define PM4_BUFFER_DATAH			0x07f4
 #define PM4_BUFFER_DATAL			0x07f8
 #define PM4_MICRO_CNTL				0x07fc
-#define VID_BUFFER_CONTROL			0x0900
-#define CAP_INT_CNTL				0x0908
-#define CAP_INT_STATUS				0x090c
-#define CAP0_BUF0_OFFSET			0x0920
-#define CAP0_BUF1_OFFSET			0x0924
-#define CAP0_BUF0_EVEN_OFFSET			0x0928
-#define CAP0_BUF1_EVEN_OFFSET			0x092c
-#define CAP0_BUF_PITCH				0x0930
-#define CAP0_V_WINDOW				0x0934
-#define CAP0_H_WINDOW				0x0938
-#define CAP0_VBI_ODD_OFFSET			0x093c
-#define CAP0_VBI_EVEN_OFFSET			0x0940
-#define CAP0_VBI_V_WINDOW			0x0944
-#define CAP0_VBI_H_WINDOW			0x0948
-#define CAP0_PORT_MODE_CNTL			0x094c
 #define CAP0_TRIG_CNTL				0x0950
-#define CAP0_DEBUG				0x0954
-#define CAP0_CONFIG				0x0958
-#define CAP0_ANC_ODD_OFFSET			0x095c
-#define CAP0_ANC_EVEN_OFFSET			0x0960
-#define CAP0_ANC_H_WINDOW			0x0964
-#define CAP0_VIDEO_SYNC_TEST			0x0968
-#define CAP0_ONESHOT_BUF_OFFSET			0x096c
-#define CAP0_BUF_STATUS				0x0970
-#define CAP0_DWNSC_XRATIO			0x0978
-#define CAP0_XSHARPNESS				0x097c
-#define CAP1_BUF0_OFFSET			0x0990
-#define CAP1_BUF1_OFFSET			0x0994
-#define CAP1_BUF0_EVEN_OFFSET			0x0998
-#define CAP1_BUF1_EVEN_OFFSET			0x099c
-#define CAP1_BUF_PITCH				0x09a0
-#define CAP1_V_WINDOW				0x09a4
-#define CAP1_H_WINDOW				0x09a8
-#define CAP1_VBI_ODD_OFFSET			0x09ac
-#define CAP1_VBI_EVEN_OFFSET			0x09b0
-#define CAP1_VBI_V_WINDOW			0x09b4
-#define CAP1_VBI_H_WINDOW			0x09b8
-#define CAP1_PORT_MODE_CNTL			0x09bc
 #define CAP1_TRIG_CNTL				0x09c0
-#define CAP1_DEBUG				0x09c4
-#define CAP1_CONFIG				0x09c8
-#define CAP1_ANC_ODD_OFFSET			0x09cc
-#define CAP1_ANC_EVEN_OFFSET			0x09d0
-#define CAP1_ANC_H_WINDOW			0x09d4
-#define CAP1_VIDEO_SYNC_TEST			0x09d8
-#define CAP1_ONESHOT_BUF_OFFSET			0x09dc
-#define CAP1_BUF_STATUS				0x09e0
-#define CAP1_DWNSC_XRATIO			0x09e8
-#define CAP1_XSHARPNESS				0x09ec
-#define BM_FRAME_BUF_OFFSET			0x0a00
-#define BM_SYSTEM_MEM_ADDR			0x0a04
-#define BM_COMMAND				0x0a08
-#define BM_STATUS				0x0a0c
-#define BM_QUEUE_STATUS				0x0a10
-#define BM_QUEUE_FREE_STATUS			0x0A14
-#define BM_CHUNK_0_VAL				0x0a18
-#define BM_CHUNK_1_VAL				0x0a1C
-#define BM_VIP0_BUF				0x0A20
-#define BM_VIP0_ACTIVE				0x0A24
-#define BM_VIP1_BUF				0x0A30
-#define BM_VIP1_ACTIVE				0x0A34
-#define BM_VIP2_BUF				0x0A40
-#define BM_VIP2_ACTIVE				0x0A44
-#define BM_VIP3_BUF				0x0A50
-#define BM_VIP3_ACTIVE				0x0A54
-#define BM_VIDCAP_BUF0				0x0a60
-#define BM_VIDCAP_BUF1				0x0a64
-#define BM_VIDCAP_BUF2				0x0a68
-#define BM_VIDCAP_ACTIVE			0x0a6c
-#define BM_GUI					0x0a80
-#define SURFACE_DELAY				0x0b00
 
 /******************************************************************************
  *                  GUI Block Memory Mapped Registers                         *
@@ -286,70 +128,6 @@
 #define BRUSH_Y_X				0x1474
 #define DP_BRUSH_BKGD_CLR			0x1478
 #define DP_BRUSH_FRGD_CLR			0x147c
-#define BRUSH_DATA0				0x1480
-#define BRUSH_DATA1				0x1484
-#define BRUSH_DATA2				0x1488
-#define BRUSH_DATA3				0x148c
-#define BRUSH_DATA4				0x1490
-#define BRUSH_DATA5				0x1494
-#define BRUSH_DATA6				0x1498
-#define BRUSH_DATA7				0x149c
-#define BRUSH_DATA8				0x14a0
-#define BRUSH_DATA9				0x14a4
-#define BRUSH_DATA10				0x14a8
-#define BRUSH_DATA11				0x14ac
-#define BRUSH_DATA12				0x14b0
-#define BRUSH_DATA13				0x14b4
-#define BRUSH_DATA14				0x14b8
-#define BRUSH_DATA15				0x14bc
-#define BRUSH_DATA16				0x14c0
-#define BRUSH_DATA17				0x14c4
-#define BRUSH_DATA18				0x14c8
-#define BRUSH_DATA19				0x14cc
-#define BRUSH_DATA20				0x14d0
-#define BRUSH_DATA21				0x14d4
-#define BRUSH_DATA22				0x14d8
-#define BRUSH_DATA23				0x14dc
-#define BRUSH_DATA24				0x14e0
-#define BRUSH_DATA25				0x14e4
-#define BRUSH_DATA26				0x14e8
-#define BRUSH_DATA27				0x14ec
-#define BRUSH_DATA28				0x14f0
-#define BRUSH_DATA29				0x14f4
-#define BRUSH_DATA30				0x14f8
-#define BRUSH_DATA31				0x14fc
-#define BRUSH_DATA32				0x1500
-#define BRUSH_DATA33				0x1504
-#define BRUSH_DATA34				0x1508
-#define BRUSH_DATA35				0x150c
-#define BRUSH_DATA36				0x1510
-#define BRUSH_DATA37				0x1514
-#define BRUSH_DATA38				0x1518
-#define BRUSH_DATA39				0x151c
-#define BRUSH_DATA40				0x1520
-#define BRUSH_DATA41				0x1524
-#define BRUSH_DATA42				0x1528
-#define BRUSH_DATA43				0x152c
-#define BRUSH_DATA44				0x1530
-#define BRUSH_DATA45				0x1534
-#define BRUSH_DATA46				0x1538
-#define BRUSH_DATA47				0x153c
-#define BRUSH_DATA48				0x1540
-#define BRUSH_DATA49				0x1544
-#define BRUSH_DATA50				0x1548
-#define BRUSH_DATA51				0x154c
-#define BRUSH_DATA52				0x1550
-#define BRUSH_DATA53				0x1554
-#define BRUSH_DATA54				0x1558
-#define BRUSH_DATA55				0x155c
-#define BRUSH_DATA56				0x1560
-#define BRUSH_DATA57				0x1564
-#define BRUSH_DATA58				0x1568
-#define BRUSH_DATA59				0x156c
-#define BRUSH_DATA60				0x1570
-#define BRUSH_DATA61				0x1574
-#define BRUSH_DATA62				0x1578
-#define BRUSH_DATA63				0x157c
 #define DST_WIDTH_X				0x1588
 #define DST_HEIGHT_WIDTH_8			0x158c
 #define SRC_X_Y					0x1590
@@ -368,22 +146,6 @@
 #define CLR_CMP_MASK				0x15cc
 #define DP_SRC_FRGD_CLR				0x15d8
 #define DP_SRC_BKGD_CLR				0x15dc
-#define GUI_SCRATCH_REG0			0x15e0
-#define GUI_SCRATCH_REG1			0x15e4
-#define GUI_SCRATCH_REG2			0x15e8
-#define GUI_SCRATCH_REG3			0x15ec
-#define GUI_SCRATCH_REG4			0x15f0
-#define GUI_SCRATCH_REG5			0x15f4
-#define LEAD_BRES_ERR				0x1600
-#define LEAD_BRES_INC				0x1604
-#define LEAD_BRES_DEC				0x1608
-#define TRAIL_BRES_ERR				0x160c
-#define TRAIL_BRES_INC				0x1610
-#define TRAIL_BRES_DEC				0x1614
-#define TRAIL_X					0x1618
-#define LEAD_BRES_LNTH				0x161c
-#define TRAIL_X_SUB				0x1620
-#define LEAD_BRES_LNTH_SUB			0x1624
 #define DST_BRES_ERR				0x1628
 #define DST_BRES_INC				0x162c
 #define DST_BRES_DEC				0x1630
@@ -395,19 +157,6 @@
 #define SC_BOTTOM				0x164c
 #define SRC_SC_RIGHT				0x1654
 #define SRC_SC_BOTTOM				0x165c
-#define AUX_SC_CNTL				0x1660
-#define AUX1_SC_LEFT				0x1664
-#define AUX1_SC_RIGHT				0x1668
-#define AUX1_SC_TOP				0x166c
-#define AUX1_SC_BOTTOM				0x1670
-#define AUX2_SC_LEFT				0x1674
-#define AUX2_SC_RIGHT				0x1678
-#define AUX2_SC_TOP				0x167c
-#define AUX2_SC_BOTTOM				0x1680
-#define AUX3_SC_LEFT				0x1684
-#define AUX3_SC_RIGHT				0x1688
-#define AUX3_SC_TOP				0x168c
-#define AUX3_SC_BOTTOM				0x1690
 #define GUI_DEBUG0				0x16a0
 #define GUI_DEBUG1				0x16a4
 #define GUI_TIMEOUT				0x16b0
@@ -437,20 +186,6 @@
 #define DP_T12_CNTL				0x178c
 #define DST_BRES_T1_LNTH			0x1790
 #define DST_BRES_T2_LNTH			0x1794
-#define HOST_DATA0				0x17c0
-#define HOST_DATA1				0x17c4
-#define HOST_DATA2				0x17c8
-#define HOST_DATA3				0x17cc
-#define HOST_DATA4				0x17d0
-#define HOST_DATA5				0x17d4
-#define HOST_DATA6				0x17d8
-#define HOST_DATA7				0x17dc
-#define HOST_DATA_LAST				0x17e0
-#define SECONDARY_SCALE_PITCH			0x1980
-#define SECONDARY_SCALE_X_INC			0x1984
-#define SECONDARY_SCALE_Y_INC			0x1988
-#define SECONDARY_SCALE_HACC			0x198c
-#define SECONDARY_SCALE_VACC			0x1990
 #define SCALE_SRC_HEIGHT_WIDTH			0x1994
 #define SCALE_OFFSET_0				0x1998
 #define SCALE_PITCH				0x199c
@@ -528,6 +263,7 @@
 
 /* DAC_CNTL bit constants */                       
 #define DAC_8BIT_EN				0x00000100
+#define DAC_MASK				0xFF000000
 
 /* GEN_RESET_CNTL bit constants */
 #define SOFT_RESET_GUI				0x00000001
@@ -545,6 +281,15 @@
 #define BUS_MASTER_DIS				0x00000040
 #define PM4_BUFFER_CNTL_NONPM4			0x00000000
 
+/* DP_DATATYPE bit constants */
+#define DST_8BPP				0x00000002
+#define DST_15BPP				0x00000003
+#define DST_16BPP				0x00000004
+#define DST_24BPP				0x00000005
+#define DST_32BPP				0x00000006
+
+#define BRUSH_SOLIDCOLOR			0x00000d00
+
 /* DP_GUI_MASTER_CNTL bit constants */
 #define	GMC_SRC_PITCH_OFFSET_DEFAULT		0x00000000
 #define GMC_DST_PITCH_OFFSET_DEFAULT		0x00000000
@@ -562,7 +307,7 @@
 
 /* DP_GUI_MASTER_CNTL ROP3 named constants */
 #define	ROP3_PATCOPY				0x00f00000
-#define ROP3_SRCCOPY				0x00cc0000   // S
+#define ROP3_SRCCOPY				0x00cc0000
 
 #define SRC_DSTCOLOR				0x00030000
 
diff -u --recursive --new-file v2.3.38/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.38/linux/drivers/video/atyfb.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/video/atyfb.c	Sat Jan  8 12:59:39 2000
@@ -4805,98 +4805,6 @@
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	struct fb_info_aty *info;
- 	unsigned int pm;
- 	
-	for (info = first_display; info != NULL; info = info->next) {
-		struct fb_fix_screeninfo fix;
-		int nb;
-		
-		atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
-		nb = fb_display[fg_console].var.yres * fix.line_length;
-
-		switch (when) {
-		case PBOOK_SLEEP_NOW:
-			/* Stop accel engine (stop bus mastering) */
-			if (info->current_par.accel_flags & FB_ACCELF_TEXT)
-				reset_engine(info);
-#if 1
-			/* Backup fb content */	
-			info->save_framebuffer = vmalloc(nb);
-			if (info->save_framebuffer)
-				memcpy(info->save_framebuffer,
-				       (void *)info->frame_buffer, nb);
-#endif
-			/* Blank display and LCD */				       
-			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);			
-			
-			/* Set chip to "suspend" mode. Note: There's an HW bug in the
-			   chip which prevents proper resync on wakeup with automatic
-			   power management, we handle suspend manually using the
-			   following (weird) sequence described by ATI. Note2:
-			   We could enable this for all Rage LT Pro chip ids */
-			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm &= ~PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm &= ~(PWR_BLON | AUTO_PWR_UP);
-				pm |= SUSPEND_NOW;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm |= PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				do {
-					pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
-				mdelay(500);
-			}
-			break;
-		case PBOOK_WAKE:
-			/* Wakeup chip */
-			if ((Gx == LG_CHIP_ID) || (Gx == LT_CHIP_ID) || (Gx == LP_CHIP_ID)) {
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm &= ~PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm |=  (PWR_BLON | AUTO_PWR_UP);
-				pm &= ~SUSPEND_NOW;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				pm |= PWR_MGT_ON;
-				aty_st_le32(POWER_MANAGEMENT, pm, info);
-				do {
-					pm = aty_ld_le32(POWER_MANAGEMENT, info);
-				} while ((pm & PWR_MGT_STATUS_MASK) != 0);
-				mdelay(500);
-			}
-#if 1
-			/* Restore fb content */			
-			if (info->save_framebuffer) {
-				memcpy((void *)info->frame_buffer,
-				       info->save_framebuffer, nb);
-				vfree(info->save_framebuffer);
-				info->save_framebuffer = 0;
-			}
-#endif
-			/* Restore display */			
-			atyfb_set_par(&info->current_par, info);
-			atyfbcon_blank(0, (struct fb_info *)info);
-			break;
-		}
-	}
-	return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
 #ifdef MODULE
 int __init init_module(void)
 {
diff -u --recursive --new-file v2.3.38/linux/fs/Config.in linux/fs/Config.in
--- v2.3.38/linux/fs/Config.in	Wed Dec 29 13:13:20 1999
+++ linux/fs/Config.in	Mon Jan 10 14:19:46 2000
@@ -53,9 +53,9 @@
    bool '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   tristate 'QNX filesystem support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS
+   tristate 'QNX4 filesystem support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS
    if [ "$CONFIG_QNX4FS_FS" != "n" ]; then
-      bool '  QNXFS write support (DANGEROUS)' CONFIG_QNX4FS_RW
+      bool '  QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW
    fi    
 fi
 tristate 'ROM filesystem support' CONFIG_ROMFS_FS
diff -u --recursive --new-file v2.3.38/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.38/linux/fs/binfmt_elf.c	Tue Nov 23 22:42:21 1999
+++ linux/fs/binfmt_elf.c	Mon Jan 10 18:15:58 2000
@@ -29,6 +29,7 @@
 #include <linux/personality.h>
 #include <linux/elfcore.h>
 #include <linux/init.h>
+#include <linux/highuid.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
@@ -1160,8 +1161,8 @@
 	psinfo.pr_zomb = psinfo.pr_sname == 'Z';
 	psinfo.pr_nice = current->priority-15;
 	psinfo.pr_flag = current->flags;
-	psinfo.pr_uid = current->uid;
-	psinfo.pr_gid = current->gid;
+	psinfo.pr_uid = NEW_TO_OLD_UID(current->uid);
+	psinfo.pr_gid = NEW_TO_OLD_GID(current->gid);
 	{
 		int i, len;
 
diff -u --recursive --new-file v2.3.38/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.3.38/linux/fs/block_dev.c	Fri Jan  7 19:13:22 2000
+++ linux/fs/block_dev.c	Sun Jan  9 16:51:37 2000
@@ -298,7 +298,7 @@
  *	since the vma has no handle.
  */
  
-int block_fsync(struct file *filp, struct dentry *dentry)
+static int block_fsync(struct file *filp, struct dentry *dentry)
 {
 	return fsync_dev(dentry->d_inode->i_rdev);
 }
@@ -604,8 +604,11 @@
 	kdev_t rdev = to_kdev_t(bdev->bd_dev); /* this should become bdev */
 	down(&bdev->bd_sem);
 	/* syncing will go here */
+	if (kind == BDEV_FILE || kind == BDEV_FS)
+		fsync_dev(rdev);
 	if (atomic_dec_and_test(&bdev->bd_openers)) {
 		/* invalidating buffers will go here */
+		invalidate_buffers(rdev);
 	}
 	if (bdev->bd_op->release) {
 		struct inode * fake_inode = get_empty_inode();
diff -u --recursive --new-file v2.3.38/linux/fs/efs/inode.c linux/fs/efs/inode.c
--- v2.3.38/linux/fs/efs/inode.c	Tue Jan  4 13:57:17 2000
+++ linux/fs/efs/inode.c	Mon Jan 10 18:15:58 2000
@@ -70,8 +70,8 @@
     
 	inode->i_mode  = be16_to_cpu(efs_inode->di_mode);
 	inode->i_nlink = be16_to_cpu(efs_inode->di_nlink);
-	inode->i_uid   = be16_to_cpu(efs_inode->di_uid);
-	inode->i_gid   = be16_to_cpu(efs_inode->di_gid);
+	inode->i_uid   = (uid_t)be16_to_cpu(efs_inode->di_uid);
+	inode->i_gid   = (gid_t)be16_to_cpu(efs_inode->di_gid);
 	inode->i_size  = be32_to_cpu(efs_inode->di_size);
 	inode->i_atime = be32_to_cpu(efs_inode->di_atime);
 	inode->i_mtime = be32_to_cpu(efs_inode->di_mtime);
diff -u --recursive --new-file v2.3.38/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- v2.3.38/linux/fs/ext2/fsync.c	Tue Dec  7 09:32:47 1999
+++ linux/fs/ext2/fsync.c	Sat Jan  8 12:49:25 2000
@@ -23,6 +23,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/locks.h>
 
 
 
@@ -40,10 +41,21 @@
 	if (!bh)
 		return 0;
 	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
-		brelse(bh);
-		return -1;
+		/* There can be a parallell read(2) that started read-I/O
+		   on the buffer so we can't assume that there's been
+		   an I/O error without first waiting I/O completation. */
+		wait_on_buffer(bh);
+		if (!buffer_uptodate(bh))
+		{
+			brelse (bh);
+			return -1;
+		}
 	}
 	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+		if (wait)
+			/* when we return from fsync all the blocks
+			   must be _just_ stored on disk */
+			wait_on_buffer(bh);
 		brelse(bh);
 		return 0;
 	}
diff -u --recursive --new-file v2.3.38/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.3.38/linux/fs/ext2/inode.c	Tue Dec 14 01:27:24 1999
+++ linux/fs/ext2/inode.c	Mon Jan 10 18:15:58 2000
@@ -24,6 +24,7 @@
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <linux/sched.h>
+#include <linux/highuid.h>
 
 
 
@@ -254,6 +255,8 @@
 	}
 	if (metadata) {
 		result = getblk (inode->i_dev, tmp, blocksize);
+		if (!buffer_uptodate(result))
+			wait_on_buffer(result);
 		memset(result->b_data, 0, blocksize);
 		mark_buffer_uptodate(result, 1);
 		mark_buffer_dirty(result, 1);
@@ -363,6 +366,8 @@
 		goto out;
 	if (metadata) {
 		result = getblk (bh->b_dev, tmp, blocksize);
+		if (!buffer_uptodate(result))
+			wait_on_buffer(result);
 		memset(result->b_data, 0, inode->i_sb->s_blocksize);
 		mark_buffer_uptodate(result, 1);
 		mark_buffer_dirty(result, 1);
@@ -542,6 +547,8 @@
 		struct buffer_head *bh;
 		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
 		if (buffer_new(&dummy)) {
+			if (!buffer_uptodate(bh))
+				wait_on_buffer(bh);
 			memset(bh->b_data, 0, inode->i_sb->s_blocksize);
 			mark_buffer_uptodate(bh, 1);
 			mark_buffer_dirty(bh, 1);
@@ -655,8 +662,12 @@
 	raw_inode = (struct ext2_inode *) (bh->b_data + offset);
 
 	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
-	inode->i_uid = le16_to_cpu(raw_inode->i_uid);
-	inode->i_gid = le16_to_cpu(raw_inode->i_gid);
+	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+	if(!(test_opt (inode->i_sb, NO_UID32))) {
+		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+	}
 	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
 	inode->i_size = le32_to_cpu(raw_inode->i_size);
 	inode->i_atime = le32_to_cpu(raw_inode->i_atime);
@@ -795,8 +806,26 @@
 	raw_inode = (struct ext2_inode *) (bh->b_data + offset);
 
 	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
-	raw_inode->i_uid = cpu_to_le16(inode->i_uid);
-	raw_inode->i_gid = cpu_to_le16(inode->i_gid);
+	if(!(test_opt(inode->i_sb, NO_UID32))) {
+		raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
+		raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+/*
+ * Fix up interoperability with old kernels. Otherwise, old inodes get
+ * re-used with the upper 16 bits of the uid/gid intact
+ */
+		if(!inode->u.ext2_i.i_dtime) {
+			raw_inode->i_uid_high = cpu_to_le16(high_16_bits(inode->i_uid));
+			raw_inode->i_gid_high = cpu_to_le16(high_16_bits(inode->i_gid));
+		} else {
+			raw_inode->i_uid_high = 0;
+			raw_inode->i_gid_high = 0;
+		}
+	} else {
+		raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(inode->i_uid));
+		raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(inode->i_gid));
+		raw_inode->i_uid_high = 0;
+		raw_inode->i_gid_high = 0;
+	}
 	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
 	raw_inode->i_size = cpu_to_le32(inode->i_size);
 	raw_inode->i_atime = cpu_to_le32(inode->i_atime);
diff -u --recursive --new-file v2.3.38/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.3.38/linux/fs/ext2/super.c	Tue Jan  4 13:57:18 2000
+++ linux/fs/ext2/super.c	Mon Jan 10 18:15:58 2000
@@ -151,6 +151,9 @@
 			*value++ = 0;
 		if (!strcmp (this_char, "bsddf"))
 			clear_opt (*mount_options, MINIX_DF);
+		else if (!strcmp (this_char, "nouid32")) {
+			set_opt (*mount_options, NO_UID32);
+		}
 		else if (!strcmp (this_char, "check")) {
 			if (!value || !*value)
 				set_opt (*mount_options, CHECK_NORMAL);
diff -u --recursive --new-file v2.3.38/linux/fs/inode.c linux/fs/inode.c
--- v2.3.38/linux/fs/inode.c	Fri Jan  7 19:13:22 2000
+++ linux/fs/inode.c	Mon Jan 10 18:15:58 2000
@@ -51,6 +51,7 @@
 static LIST_HEAD(inode_in_use);
 static LIST_HEAD(inode_unused);
 static struct list_head inode_hashtable[HASH_SIZE];
+static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */
 
 /*
  * A simple spinlock to protect the list manipulations.
@@ -632,7 +633,9 @@
 
 void insert_inode_hash(struct inode *inode)
 {
-	struct list_head *head = inode_hashtable + hash(inode->i_sb, inode->i_ino);
+	struct list_head *head = &anon_hash_chain;
+	if (inode->i_sb)
+		head = inode_hashtable + hash(inode->i_sb, inode->i_ino);
 	spin_lock(&inode_lock);
 	list_add(&inode->i_hash, head);
 	spin_unlock(&inode_lock);
diff -u --recursive --new-file v2.3.38/linux/fs/iobuf.c linux/fs/iobuf.c
--- v2.3.38/linux/fs/iobuf.c	Fri Oct 22 13:21:52 1999
+++ linux/fs/iobuf.c	Sat Jan  8 13:03:07 2000
@@ -88,7 +88,7 @@
 		return 0;
 	}
 	
-	memcpy (maplist,  iobuf->maplist,   wanted * sizeof(struct page **));
+	memcpy (maplist, iobuf->maplist, iobuf->array_len * sizeof(struct page **));
 
 	if (iobuf->array_len > KIO_STATIC_PAGES)
 		kfree (iobuf->maplist);
diff -u --recursive --new-file v2.3.38/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.3.38/linux/fs/minix/inode.c	Mon Dec 20 18:48:22 1999
+++ linux/fs/minix/inode.c	Mon Jan 10 18:15:58 2000
@@ -20,6 +20,7 @@
 #include <linux/locks.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/highuid.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -1044,8 +1045,8 @@
 	raw_inode = ((struct minix_inode *) bh->b_data) +
 		    (ino-1)%MINIX_INODES_PER_BLOCK;
 	inode->i_mode = raw_inode->i_mode;
-	inode->i_uid = raw_inode->i_uid;
-	inode->i_gid = raw_inode->i_gid;
+	inode->i_uid = (uid_t)raw_inode->i_uid;
+	inode->i_gid = (gid_t)raw_inode->i_gid;
 	inode->i_nlink = raw_inode->i_nlinks;
 	inode->i_size = raw_inode->i_size;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
@@ -1092,8 +1093,8 @@
 	raw_inode = ((struct minix2_inode *) bh->b_data) +
 		    (ino-1)%MINIX2_INODES_PER_BLOCK;
 	inode->i_mode = raw_inode->i_mode;
-	inode->i_uid = raw_inode->i_uid;
-	inode->i_gid = raw_inode->i_gid;
+	inode->i_uid = (uid_t)raw_inode->i_uid;
+	inode->i_gid = (gid_t)raw_inode->i_gid;
 	inode->i_nlink = raw_inode->i_nlinks;
 	inode->i_size = raw_inode->i_size;
 	inode->i_mtime = raw_inode->i_mtime;
@@ -1149,8 +1150,8 @@
 	raw_inode = ((struct minix_inode *)bh->b_data) +
 		(ino-1)%MINIX_INODES_PER_BLOCK;
 	raw_inode->i_mode = inode->i_mode;
-	raw_inode->i_uid = inode->i_uid;
-	raw_inode->i_gid = inode->i_gid;
+	raw_inode->i_uid = fs_high2lowuid(inode->i_uid);
+	raw_inode->i_gid = fs_high2lowgid(inode->i_gid);
 	raw_inode->i_nlinks = inode->i_nlink;
 	raw_inode->i_size = inode->i_size;
 	raw_inode->i_time = inode->i_mtime;
@@ -1187,8 +1188,8 @@
 	raw_inode = ((struct minix2_inode *)bh->b_data) +
 		(ino-1)%MINIX2_INODES_PER_BLOCK;
 	raw_inode->i_mode = inode->i_mode;
-	raw_inode->i_uid = inode->i_uid;
-	raw_inode->i_gid = inode->i_gid;
+	raw_inode->i_uid = fs_high2lowuid(inode->i_uid);
+	raw_inode->i_gid = fs_high2lowgid(inode->i_gid);
 	raw_inode->i_nlinks = inode->i_nlink;
 	raw_inode->i_size = inode->i_size;
 	raw_inode->i_mtime = inode->i_mtime;
diff -u --recursive --new-file v2.3.38/linux/fs/ncpfs/ioctl.c linux/fs/ncpfs/ioctl.c
--- v2.3.38/linux/fs/ncpfs/ioctl.c	Wed Dec  8 14:11:27 1999
+++ linux/fs/ncpfs/ioctl.c	Mon Jan 10 18:15:58 2000
@@ -15,6 +15,7 @@
 #include <linux/ioctl.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/highuid.h>
 
 #include <linux/ncp_fs.h>
 
@@ -128,7 +129,7 @@
 			return -EINVAL;
 		}
 		/* TODO: info.addr = server->m.serv_addr; */
-		info.mounted_uid	= server->m.mounted_uid;
+		info.mounted_uid	= NEW_TO_OLD_UID(server->m.mounted_uid);
 		info.connection		= server->connection;
 		info.buffer_size	= server->buffer_size;
 		info.volume_number	= NCP_FINFO(inode)->volNumber;
@@ -143,9 +144,14 @@
 		    && (current->uid != server->m.mounted_uid)) {
 			return -EACCES;
 		}
-		if ((result = verify_area(VERIFY_WRITE, (uid_t *) arg,
-					  sizeof(uid_t))) != 0) {
-			return result;
+		put_user(high2lowuid(server->m.mounted_uid), (old_uid_t *) arg);
+		return 0;
+
+	case NCP_IOC_GETMOUNTUID32:
+
+		if ((permission(inode, MAY_READ) != 0)
+		    && (current->uid != server->m.mounted_uid)) {
+			return -EACCES;
 		}
 		put_user(server->m.mounted_uid, (uid_t *) arg);
 		return 0;
diff -u --recursive --new-file v2.3.38/linux/fs/ncpfs/ncplib_kernel.c linux/fs/ncpfs/ncplib_kernel.c
--- v2.3.38/linux/fs/ncpfs/ncplib_kernel.c	Wed Dec  8 14:11:27 1999
+++ linux/fs/ncpfs/ncplib_kernel.c	Mon Jan 10 12:13:06 2000
@@ -617,10 +617,8 @@
 	target->server_file_handle = ncp_reply_dword(server, 0);
 	target->open_create_action = ncp_reply_byte(server, 4);
 
-	if (dir != NULL) {
-		/* in target there's a new finfo to fill */
-		ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i));
-	}
+	/* in target there's a new finfo to fill */
+	ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i));
 	ConvertToNWfromDWORD(target->server_file_handle, target->file_handle);
 
 out:
diff -u --recursive --new-file v2.3.38/linux/fs/ntfs/ntfstypes.h linux/fs/ntfs/ntfstypes.h
--- v2.3.38/linux/fs/ntfs/ntfstypes.h	Mon Apr 12 10:05:58 1999
+++ linux/fs/ntfs/ntfstypes.h	Mon Jan 10 18:15:58 2000
@@ -72,11 +72,11 @@
 #endif
 #ifndef NTFS_UID_T
 #define NTFS_UID_T
-typedef __kernel_uid_t ntfs_uid_t;
+typedef uid_t ntfs_uid_t;
 #endif
 #ifndef NTFS_GID_T
 #define NTFS_GID_T
-typedef __kernel_gid_t ntfs_gid_t;
+typedef gid_t ntfs_gid_t;
 #endif
 #ifndef NTFS_SIZE_T
 #define NTFS_SIZE_T
diff -u --recursive --new-file v2.3.38/linux/fs/partitions/acorn.c linux/fs/partitions/acorn.c
--- v2.3.38/linux/fs/partitions/acorn.c	Mon Oct  4 15:49:30 1999
+++ linux/fs/partitions/acorn.c	Mon Jan 10 14:05:33 2000
@@ -14,9 +14,10 @@
 #include <linux/genhd.h>
 #include <linux/fs.h>
 
+#include "check.h"
 #include "acorn.h"
 
-extern void add_gd_partition(struct gendisk *hd, unsigned int minor, unsigned int start, unsigned int size);
+extern void add_gd_partition(struct gendisk *hd, int minor, int start, int size);
 
 static void
 adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads,
diff -u --recursive --new-file v2.3.38/linux/fs/proc/proc_devtree.c linux/fs/proc/proc_devtree.c
--- v2.3.38/linux/fs/proc/proc_devtree.c	Tue Dec  7 09:32:48 1999
+++ linux/fs/proc/proc_devtree.c	Sat Jan  8 12:59:39 2000
@@ -59,8 +59,8 @@
 		 * Unfortunately proc_register puts each new entry
 		 * at the beginning of the list.  So we rearrange them.
 		 */
-		ent = create_proc_read_entry(de, 0, pp->name,
-						property_read_proc, pp);
+		ent = create_proc_read_entry(pp->name, S_IRUGO, de,
+					     property_read_proc, pp);
 		if (ent == 0)
 			break;
 		ent->size = pp->length;
@@ -77,7 +77,7 @@
 		l = strlen(p);
 		if (l > 2 && p[l-2] == '@' && p[l-1] == '0')
 			l -= 2;
-		ent = proc_mkdir(de, p);
+		ent = proc_mkdir(p, de);
 		if (ent == 0)
 			break;
 		*lastp = ent;
@@ -99,7 +99,7 @@
 			if (sib->name && strcmp(sib->name, child->name) == 0)
 				break;
 		if (sib == child && strncmp(p, child->name, l) != 0) {
-			al = proc_symlink(de, child->name, ent->name);
+			al = proc_symlink(child->name, de, ent->name);
 			if (al == 0)
 				break;
 			*lastp = al;
@@ -109,7 +109,7 @@
 		/*
 		 * Add another directory with the @address part as its name.
 		 */
-		al = proc_symlink(de, at, ent->name);
+		al = proc_symlink(at, de, ent->name);
 		if (al == 0)
 			break;
 		proc_register(de, al);
diff -u --recursive --new-file v2.3.38/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c
--- v2.3.38/linux/fs/proc/procfs_syms.c	Tue Nov 23 22:42:21 1999
+++ linux/fs/proc/procfs_syms.c	Sat Jan  8 12:46:17 2000
@@ -17,6 +17,7 @@
 EXPORT_SYMBOL(proc_root_fs);
 EXPORT_SYMBOL(proc_net);
 EXPORT_SYMBOL(proc_bus);
+EXPORT_SYMBOL(proc_root_driver);
 
 static struct file_system_type proc_fs_type = {
 	"proc", 
diff -u --recursive --new-file v2.3.38/linux/fs/qnx4/README linux/fs/qnx4/README
--- v2.3.38/linux/fs/qnx4/README	Wed Dec 29 13:13:21 1999
+++ linux/fs/qnx4/README	Mon Jan 10 14:19:46 2000
@@ -6,4 +6,4 @@
 
 Richard "Scuba" A. Frowijn     <scuba@wxs.nl>
 Frank "Jedi/Sector One" Denis  <j@4u.net>
-Anders Larsen                  <al@alarsen.net>
+Anders Larsen                  <al@alarsen.net> (Maintainer)
diff -u --recursive --new-file v2.3.38/linux/fs/qnx4/bitmap.c linux/fs/qnx4/bitmap.c
--- v2.3.38/linux/fs/qnx4/bitmap.c	Wed Dec 29 13:13:21 1999
+++ linux/fs/qnx4/bitmap.c	Mon Jan 10 14:19:46 2000
@@ -86,6 +86,8 @@
 	return qnx4_count_free_blocks(sb) * QNX4_INODES_PER_BLOCK;	/* FIXME */
 }
 
+#ifdef CONFIG_QNX4FS_RW
+
 int qnx4_is_free(struct super_block *sb, long block)
 {
 	int start = sb->u.qnx4_sb.BitMap->di_first_xtnt.xtnt_blk - 1;
@@ -114,8 +116,6 @@
 
 	return ret;
 }
-
-#ifdef CONFIG_QNX4FS_RW
 
 int qnx4_set_bitmap(struct super_block *sb, long block, int busy)
 {
diff -u --recursive --new-file v2.3.38/linux/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- v2.3.38/linux/fs/qnx4/dir.c	Wed Dec 29 13:13:21 1999
+++ linux/fs/qnx4/dir.c	Mon Jan 10 14:19:46 2000
@@ -37,8 +37,7 @@
 	while (filp->f_pos < inode->i_size) {
 		blknum = qnx4_block_map( inode, filp->f_pos / QNX4_BLOCK_SIZE );
 		bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
-		if(bh==NULL)
-		{
+		if(bh==NULL) {
 			printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
 			break;
 		}
@@ -57,8 +56,7 @@
 					QNX4DEBUG(("qnx4_readdir:%.*s\n", size, de->di_fname));
 					if ( ( de->di_status & QNX4_FILE_LINK ) == 0 )
 						ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
-					else
-					{
+					else {
 						le  = (struct qnx4_link_info*)de;
 						ino = ( le->dl_inode_blk - 1 ) *
 							QNX4_INODES_PER_BLOCK +
diff -u --recursive --new-file v2.3.38/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.3.38/linux/fs/qnx4/inode.c	Wed Dec 29 13:13:21 1999
+++ linux/fs/qnx4/inode.c	Mon Jan 10 18:15:58 2000
@@ -22,6 +22,7 @@
 #include <linux/fs.h>
 #include <linux/locks.h>
 #include <linux/init.h>
+#include <linux/highuid.h>
 
 #include <asm/uaccess.h>
 
@@ -98,8 +99,8 @@
 	raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
 	    (ino % QNX4_INODES_PER_BLOCK);
 	raw_inode->di_mode = inode->i_mode;
-	raw_inode->di_uid = inode->i_uid;
-	raw_inode->di_gid = inode->i_gid;
+	raw_inode->di_uid = fs_high2lowuid(inode->i_uid);
+	raw_inode->di_gid = fs_high2lowgid(inode->i_gid);
 	raw_inode->di_nlink = inode->i_nlink;
 	raw_inode->di_size = inode->i_size;
 	raw_inode->di_mtime = inode->i_mtime;
@@ -147,23 +148,16 @@
 	return 0;
 }
 
-struct buffer_head *inode_getblk(struct inode *inode, int nr,
+struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
 				 int create)
 {
-	int tmp;
-	int tst;
 	struct buffer_head *result = NULL;
 
-	tst = nr;
-      repeat:
-	tmp = tst;
-	if (tmp) {
-		result = getblk(inode->i_dev, tmp, QNX4_BLOCK_SIZE);
-		if (tmp == tst) {
-			return result;
-		}
-		brelse(result);
-		goto repeat;
+	if ( nr >= 0 )
+		nr = qnx4_block_map( inode, nr );
+	if (nr) {
+		result = getblk(inode->i_dev, nr, QNX4_BLOCK_SIZE);
+		return result;
 	}
 	if (!create) {
 		return NULL;
@@ -190,7 +184,7 @@
 {
 	struct buffer_head *bh;
 
-	bh = inode_getblk(inode, block, create);
+	bh = qnx4_getblk(inode, block, create);
 	if (!bh || buffer_uptodate(bh)) {
 		return bh;
 	}
@@ -211,15 +205,12 @@
 	QNX4DEBUG(("qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock));
 
 	phys = qnx4_block_map( inode, iblock );
-	if ( phys )
-	{
+	if ( phys ) {
 		// logical block is before EOF
 		bh->b_dev     = inode->i_dev;
 		bh->b_blocknr = phys;
 		bh->b_state  |= (1UL << BH_Mapped);
-	}
-	else if ( create )
-	{
+	} else if ( create ) {
 		// to be done.
 	}
 	return 0;
@@ -235,44 +226,35 @@
 	struct qnx4_inode_info *qnx4_inode = &inode->u.qnx4_i;
 	qnx4_nxtnt_t nxtnt = qnx4_inode->i_num_xtnts;
 
-	if ( iblock < qnx4_inode->i_first_xtnt.xtnt_size )
-	{
+	if ( iblock < qnx4_inode->i_first_xtnt.xtnt_size ) {
 		// iblock is in the first extent. This is easy.
 		block = qnx4_inode->i_first_xtnt.xtnt_blk + iblock - 1;
-	}
-	else
-	{
+	} else {
 		// iblock is beyond first extent. We have to follow the extent chain.
 		i_xblk = qnx4_inode->i_xblk;
 		offset = iblock - qnx4_inode->i_first_xtnt.xtnt_size;
 		ix = 0;
-		while ( --nxtnt > 0 )
-		{
-			if ( ix == 0 )
-			{
+		while ( --nxtnt > 0 ) {
+			if ( ix == 0 ) {
 				// read next xtnt block.
 				bh = bread( inode->i_dev, i_xblk - 1, QNX4_BLOCK_SIZE );
-				if ( !bh )
-				{
+				if ( !bh ) {
 					QNX4DEBUG(("qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
 					return -EIO;
 				}
 				xblk = (struct qnx4_xblk*)bh->b_data;
-				if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) )
-				{
+				if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) {
 					QNX4DEBUG(("qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
-					break;
+					return -EIO;
 				}
 			}
-			if ( offset < xblk->xblk_xtnts[ix].xtnt_size )
-			{
+			if ( offset < xblk->xblk_xtnts[ix].xtnt_size ) {
 				// got it!
 				block = xblk->xblk_xtnts[ix].xtnt_blk + offset - 1;
 				break;
 			}
 			offset -= xblk->xblk_xtnts[ix].xtnt_size;
-			if ( ++ix > QNX4_MAX_XTNTS_PER_XBLK )
-			{
+			if ( ++ix >= xblk->xblk_num_xtnts ) {
 				i_xblk = xblk->xblk_next_xblk;
 				ix = 0;
 				brelse( bh );
@@ -468,8 +450,8 @@
 	    (ino % QNX4_INODES_PER_BLOCK);
 
 	inode->i_mode = raw_inode->di_mode;
-	inode->i_uid = raw_inode->di_uid;
-	inode->i_gid = raw_inode->di_gid;
+	inode->i_uid = (uid_t)raw_inode->di_uid;
+	inode->i_gid = (gid_t)raw_inode->di_gid;
 	inode->i_nlink = raw_inode->di_nlink;
 	inode->i_size = raw_inode->di_size;
 	inode->i_mtime = raw_inode->di_mtime;
diff -u --recursive --new-file v2.3.38/linux/fs/qnx4/namei.c linux/fs/qnx4/namei.c
--- v2.3.38/linux/fs/qnx4/namei.c	Wed Dec 29 13:13:21 1999
+++ linux/fs/qnx4/namei.c	Mon Jan 10 14:19:46 2000
@@ -33,7 +33,6 @@
 		      struct buffer_head *bh, unsigned long *offset)
 {
 	struct qnx4_inode_entry *de;
-	struct qnx4_link_info *le;
 	int namelen, thislen;
 
 	if (bh == NULL) {
@@ -80,8 +79,7 @@
 	block = offset = blkofs = 0;
 	while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) {
 		if (!bh) {
-			block = qnx4_block_map( dir, blkofs );
-			bh = qnx4_bread(dir, block, 0);
+			bh = qnx4_bread(dir, blkofs, 0);
 			if (!bh) {
 				blkofs++;
 				continue;
@@ -89,6 +87,7 @@
 		}
 		*res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset);
 		if (qnx4_match(len, name, bh, &offset)) {
+			block = qnx4_block_map( dir, blkofs );
 			*ino = block * QNX4_INODES_PER_BLOCK +
 			    (offset / QNX4_DIR_ENTRY_SIZE) - 1;
 			return bh;
diff -u --recursive --new-file v2.3.38/linux/fs/qnx4/symlinks.c linux/fs/qnx4/symlinks.c
--- v2.3.38/linux/fs/qnx4/symlinks.c	Wed Dec 29 13:13:21 1999
+++ linux/fs/qnx4/symlinks.c	Mon Jan 10 14:19:46 2000
@@ -11,20 +11,8 @@
  * 21-06-1998 by Frank Denis : ugly changes to make it compile on Linux 2.1.99+
  */
 
-/* THIS FILE HAS TO BE REWRITTEN */
-
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/qnx4_fs.h>
-#include <linux/stat.h>
-
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
-static int qnx4_readlink(struct dentry *, char *, int);
-static struct dentry *qnx4_follow_link(struct dentry *, struct dentry *, unsigned int follow);
 
 /*
  * symlinks can't do much...
diff -u --recursive --new-file v2.3.38/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c
--- v2.3.38/linux/fs/smbfs/ioctl.c	Thu Dec 11 11:25:54 1997
+++ linux/fs/smbfs/ioctl.c	Mon Jan 10 18:15:58 2000
@@ -11,6 +11,7 @@
 #include <linux/ioctl.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/highuid.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smb_mount.h>
@@ -27,6 +28,9 @@
 	switch (cmd)
 	{
 	case SMB_IOC_GETMOUNTUID:
+		result = put_user(high2lowuid(server->mnt->mounted_uid), (old_uid_t *) arg);
+		break;
+	case SMB_IOC_GETMOUNTUID32:
 		result = put_user(server->mnt->mounted_uid, (uid_t *) arg);
 		break;
 
diff -u --recursive --new-file v2.3.38/linux/fs/stat.c linux/fs/stat.c
--- v2.3.38/linux/fs/stat.c	Wed Dec 29 13:13:21 1999
+++ linux/fs/stat.c	Mon Jan 10 18:15:58 2000
@@ -8,6 +8,7 @@
 #include <linux/errno.h>
 #include <linux/file.h>
 #include <linux/smp_lock.h>
+#include <linux/highuid.h>
 
 #include <asm/uaccess.h>
 
@@ -45,8 +46,8 @@
 	tmp.st_ino = inode->i_ino;
 	tmp.st_mode = inode->i_mode;
 	tmp.st_nlink = inode->i_nlink;
-	tmp.st_uid = inode->i_uid;
-	tmp.st_gid = inode->i_gid;
+	SET_OLDSTAT_UID(tmp, inode->i_uid);
+	SET_OLDSTAT_GID(tmp, inode->i_gid);
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 	tmp.st_size = inode->i_size;
 	tmp.st_atime = inode->i_atime;
@@ -67,8 +68,8 @@
 	tmp.st_ino = inode->i_ino;
 	tmp.st_mode = inode->i_mode;
 	tmp.st_nlink = inode->i_nlink;
-	tmp.st_uid = inode->i_uid;
-	tmp.st_gid = inode->i_gid;
+	SET_STAT_UID(tmp, inode->i_uid);
+	SET_STAT_GID(tmp, inode->i_gid);
 	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 	tmp.st_size = inode->i_size;
 	tmp.st_atime = inode->i_atime;
diff -u --recursive --new-file v2.3.38/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.3.38/linux/fs/sysv/inode.c	Thu Nov 18 20:25:37 1999
+++ linux/fs/sysv/inode.c	Mon Jan 10 18:15:58 2000
@@ -33,6 +33,7 @@
 #include <linux/locks.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/highuid.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
@@ -1032,8 +1033,8 @@
 		mode = from_coh_imode(mode);
 	/* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */
 	inode->i_mode = mode;
-	inode->i_uid = raw_inode->i_uid;
-	inode->i_gid = raw_inode->i_gid;
+	inode->i_uid = (uid_t)raw_inode->i_uid;
+	inode->i_gid = (gid_t)raw_inode->i_gid;
 	inode->i_nlink = raw_inode->i_nlink;
 	if (sb->sv_convert) {
 		inode->i_size = from_coh_ulong(raw_inode->i_size);
@@ -1113,8 +1114,8 @@
 	if (sb->sv_kludge_symlinks)
 		mode = to_coh_imode(mode);
 	raw_inode->i_mode = mode;
-	raw_inode->i_uid = inode->i_uid;
-	raw_inode->i_gid = inode->i_gid;
+	raw_inode->i_uid = fs_high2lowuid(inode->i_uid);
+	raw_inode->i_gid = fs_high2lowgid(inode->i_gid);
 	raw_inode->i_nlink = inode->i_nlink;
 	if (sb->sv_convert) {
 		raw_inode->i_size = to_coh_ulong(inode->i_size);
diff -u --recursive --new-file v2.3.38/linux/fs/udf/misc.c linux/fs/udf/misc.c
--- v2.3.38/linux/fs/udf/misc.c	Thu Nov 11 20:11:51 1999
+++ linux/fs/udf/misc.c	Mon Jan 10 18:15:58 2000
@@ -68,16 +68,12 @@
 {
 	if ( uidin == -1 )
 		return 0;
-	if ( uidin > (64*1024U - 1) ) /* 16 bit UID */
-		return 0;
 	return uidin;
 }
 
 gid_t udf_convert_gid(int gidin)
 {
 	if ( gidin == -1 )
-		return 0;
-	if ( gidin > (64*1024U - 1) ) /* 16 bit GID */
 		return 0;
 	return gidin;
 }
diff -u --recursive --new-file v2.3.38/linux/fs/ufs/ialloc.c linux/fs/ufs/ialloc.c
--- v2.3.38/linux/fs/ufs/ialloc.c	Sun Jan 17 18:32:26 1999
+++ linux/fs/ufs/ialloc.c	Mon Jan 10 18:15:58 2000
@@ -289,8 +289,6 @@
 	inode->i_blocks = 0;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->u.ufs_i.i_flags = dir->u.ufs_i.i_flags;
-	inode->u.ufs_i.i_uid = inode->i_uid;
-	inode->u.ufs_i.i_gid = inode->i_gid;
 	inode->u.ufs_i.i_lastfrag = 0;
 	inode->i_op = NULL;
 
diff -u --recursive --new-file v2.3.38/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.3.38/linux/fs/ufs/inode.c	Tue Dec 14 01:27:24 1999
+++ linux/fs/ufs/inode.c	Mon Jan 10 18:15:58 2000
@@ -54,11 +54,11 @@
 static void ufs_print_inode(struct inode * inode)
 {
 	unsigned swab = inode->i_sb->u.ufs_sb.s_swab;
-	printk("ino %lu  mode 0%6.6o  nlink %d  uid %d  uid32 %u"
-	       "  gid %d  gid32 %u  size %lu blocks %lu\n",
+	printk("ino %lu  mode 0%6.6o  nlink %d  uid %d  gid %d"
+	       "  size %lu blocks %lu\n",
 	       inode->i_ino, inode->i_mode, inode->i_nlink,
-	       inode->i_uid, inode->u.ufs_i.i_uid, inode->i_gid, 
-	       inode->u.ufs_i.i_gid, inode->i_size, inode->i_blocks);
+	       inode->i_uid, inode->i_gid, 
+	       inode->i_size, inode->i_blocks);
 	printk("  db <%u %u %u %u %u %u %u %u %u %u %u %u>\n",
 		SWAB32(inode->u.ufs_i.i_u1.i_data[0]),
 		SWAB32(inode->u.ufs_i.i_u1.i_data[1]),
@@ -578,17 +578,10 @@
 		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
 	
 	/*
-	 * Linux has only 16-bit uid and gid, so we can't support EFT.
-	 * Files are dynamically chown()ed to root.
+	 * Linux now has 32-bit uid and gid, so we can support EFT.
 	 */
-	inode->i_uid = inode->u.ufs_i.i_uid = ufs_get_inode_uid(ufs_inode);
-	inode->i_gid = inode->u.ufs_i.i_gid = ufs_get_inode_gid(ufs_inode);
-	if (inode->u.ufs_i.i_uid >= UFS_USEEFT) {
-		inode->i_uid = 0;
-	}
-	if (inode->u.ufs_i.i_gid >= UFS_USEEFT) {
-		inode->i_gid = 0;
-	}
+	inode->i_uid = ufs_get_inode_uid(ufs_inode);
+	inode->i_gid = ufs_get_inode_gid(ufs_inode);
 	
 	/*
 	 * Linux i_size can be 32 on some architectures. We will mark 
@@ -678,15 +671,8 @@
 	ufs_inode->ui_mode = SWAB16(inode->i_mode);
 	ufs_inode->ui_nlink = SWAB16(inode->i_nlink);
 
-	if (inode->i_uid == 0 && inode->u.ufs_i.i_uid >= UFS_USEEFT)
-		ufs_set_inode_uid (ufs_inode, inode->u.ufs_i.i_uid);
-	else
-		ufs_set_inode_uid (ufs_inode, inode->i_uid);
-
-	if (inode->i_gid == 0 && inode->u.ufs_i.i_gid >= UFS_USEEFT)
-		ufs_set_inode_gid (ufs_inode, inode->u.ufs_i.i_gid);
-	else
-		ufs_set_inode_gid (ufs_inode, inode->i_gid);
+	ufs_set_inode_uid (ufs_inode, inode->i_uid);
+	ufs_set_inode_gid (ufs_inode, inode->i_gid);
 		
 	ufs_inode->ui_size = SWAB64((u64)inode->i_size);
 	ufs_inode->ui_atime.tv_sec = SWAB32(inode->i_atime);
diff -u --recursive --new-file v2.3.38/linux/include/asm-alpha/ipcbuf.h linux/include/asm-alpha/ipcbuf.h
--- v2.3.38/linux/include/asm-alpha/ipcbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/ipcbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,28 @@
+#ifndef _ALPHA_IPCBUF_H
+#define _ALPHA_IPCBUF_H
+
+/* 
+ * The ipc64_perm structure for alpha architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit seq
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct ipc64_perm
+{
+	__kernel_key_t	key;
+	__kernel_uid_t	uid;
+	__kernel_gid_t	gid;
+	__kernel_uid_t	cuid;
+	__kernel_gid_t	cgid;
+	__kernel_mode_t	mode; 
+	unsigned short	seq;
+	unsigned short	__pad1;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
+
+#endif /* _ALPHA_IPCBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-alpha/msgbuf.h linux/include/asm-alpha/msgbuf.h
--- v2.3.38/linux/include/asm-alpha/msgbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/msgbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,27 @@
+#ifndef _ALPHA_MSGBUF_H
+#define _ALPHA_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for alpha architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused1;
+	unsigned long  __unused2;
+};
+
+#endif /* _ALPHA_MSGBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-alpha/posix_types.h linux/include/asm-alpha/posix_types.h
--- v2.3.38/linux/include/asm-alpha/posix_types.h	Tue Dec 14 01:27:24 1999
+++ linux/include/asm-alpha/posix_types.h	Mon Jan 10 18:15:58 2000
@@ -26,6 +26,10 @@
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
 typedef unsigned long	__kernel_sigset_t;	/* at least 32 bits */
+typedef unsigned short	__kernel_uid16_t;
+typedef unsigned short	__kernel_gid16_t;
+typedef unsigned int	__kernel_uid32_t;
+typedef unsigned int	__kernel_gid32_t;
 
 typedef struct {
 	int	val[2];
diff -u --recursive --new-file v2.3.38/linux/include/asm-alpha/sembuf.h linux/include/asm-alpha/sembuf.h
--- v2.3.38/linux/include/asm-alpha/sembuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/sembuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,22 @@
+#ifndef _ALPHA_SEMBUF_H
+#define _ALPHA_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for alpha architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct semid64_ds {
+	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;		/* last semop time */
+	__kernel_time_t	sem_ctime;		/* last change time */
+	unsigned long	sem_nsems;		/* no. of semaphores in array */
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+};
+
+#endif /* _ALPHA_SEMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-alpha/shmbuf.h linux/include/asm-alpha/shmbuf.h
--- v2.3.38/linux/include/asm-alpha/shmbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-alpha/shmbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,38 @@
+#ifndef _ALPHA_SHMBUF_H
+#define _ALPHA_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for alpha architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 64-bit values
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	__kernel_time_t		shm_ctime;	/* last change time */
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _ALPHA_SHMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-arm/ipcbuf.h linux/include/asm-arm/ipcbuf.h
--- v2.3.38/linux/include/asm-arm/ipcbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/ipcbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,29 @@
+#ifndef __ASMARM_IPCBUF_H
+#define __ASMARM_IPCBUF_H
+
+/*
+ * The ipc64_perm structure for arm architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm
+{
+	__kernel_key_t		key;
+	__kernel_uid32_t	uid;
+	__kernel_gid32_t	gid;
+	__kernel_uid32_t	cuid;
+	__kernel_gid32_t	cgid;
+	__kernel_mode_t		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+#endif /* __ASMARM_IPCBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-arm/msgbuf.h linux/include/asm-arm/msgbuf.h
--- v2.3.38/linux/include/asm-arm/msgbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/msgbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,31 @@
+#ifndef _ASMARM_MSGBUF_H
+#define _ASMARM_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for arm architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	unsigned long	__unused1;
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	unsigned long	__unused2;
+	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long	__unused3;
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+#endif /* _ASMARM_MSGBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-arm/posix_types.h linux/include/asm-arm/posix_types.h
--- v2.3.38/linux/include/asm-arm/posix_types.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/posix_types.h	Mon Jan 10 18:15:58 2000
@@ -32,6 +32,16 @@
 typedef long			__kernel_clock_t;
 typedef int			__kernel_daddr_t;
 typedef char *			__kernel_caddr_t;
+typedef unsigned short		__kernel_uid16_t;
+typedef unsigned short		__kernel_gid16_t;
+typedef unsigned int		__kernel_uid32_t;
+typedef unsigned int		__kernel_gid32_t;
+
+#ifdef __KERNEL__
+#define UID16_COMPAT_NEEDED
+typedef unsigned short		__kernel_old_uid_t;
+typedef unsigned short		__kernel_old_gid_t;
+#endif /* __KERNEL__ */
 
 #ifdef __GNUC__
 typedef long long		__kernel_loff_t;
diff -u --recursive --new-file v2.3.38/linux/include/asm-arm/sembuf.h linux/include/asm-arm/sembuf.h
--- v2.3.38/linux/include/asm-arm/sembuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/sembuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,25 @@
+#ifndef _ASMARM_SEMBUF_H
+#define _ASMARM_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for arm architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;		/* last semop time */
+	unsigned long	__unused1;
+	__kernel_time_t	sem_ctime;		/* last change time */
+	unsigned long	__unused2;
+	unsigned long	sem_nsems;		/* no. of semaphores in array */
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _ASMARM_SEMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-arm/shmbuf.h linux/include/asm-arm/shmbuf.h
--- v2.3.38/linux/include/asm-arm/shmbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/shmbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,42 @@
+#ifndef _ASMARM_SHMBUF_H
+#define _ASMARM_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for arm architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	unsigned long		__unused1;
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	unsigned long		__unused2;
+	__kernel_time_t		shm_ctime;	/* last change time */
+	unsigned long		__unused3;
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused4;
+	unsigned long		__unused5;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _ASMARM_SHMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-arm/siginfo.h linux/include/asm-arm/siginfo.h
--- v2.3.38/linux/include/asm-arm/siginfo.h	Wed Jul 28 10:30:10 1999
+++ linux/include/asm-arm/siginfo.h	Mon Jan 10 18:15:58 2000
@@ -24,7 +24,8 @@
 		/* kill() */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
+			uid_t _uid32;		/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
@@ -36,17 +37,19 @@
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
 			sigval_t _sigval;
+			uid_t _uid32;		/* sender's uid */
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
+			uid_t _uid32;		/* sender's uid */
 		} _sigchld;
 
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -62,11 +65,18 @@
 	} _sifields;
 } siginfo_t;
 
+#define UID16_SIGINFO_COMPAT_NEEDED
+
 /*
  * How these fields are to be accessed.
  */
 #define si_pid		_sifields._kill._pid
+#ifdef __KERNEL__
+#define si_uid		_sifields._kill._uid32
+#define si_uid16	_sifields._kill._uid
+#else
 #define si_uid		_sifields._kill._uid
+#endif /* __KERNEL__ */
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
diff -u --recursive --new-file v2.3.38/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.3.38/linux/include/asm-arm/unistd.h	Mon Dec 20 18:48:22 1999
+++ linux/include/asm-arm/unistd.h	Mon Jan 10 18:15:58 2000
@@ -205,6 +205,25 @@
 #define __NR_stat64			(__NR_SYSCALL_BASE+195)
 #define __NR_lstat64			(__NR_SYSCALL_BASE+196)
 #define __NR_fstat64			(__NR_SYSCALL_BASE+197)
+#define __NR_lchown32			(__NR_SYSCALL_BASE+198)
+#define __NR_getuid32			(__NR_SYSCALL_BASE+199)
+#define __NR_getgid32			(__NR_SYSCALL_BASE+200)
+#define __NR_geteuid32			(__NR_SYSCALL_BASE+201)
+#define __NR_getegid32			(__NR_SYSCALL_BASE+202)
+#define __NR_setreuid32			(__NR_SYSCALL_BASE+203)
+#define __NR_setregid32			(__NR_SYSCALL_BASE+204)
+#define __NR_getgroups32		(__NR_SYSCALL_BASE+205)
+#define __NR_setgroups32		(__NR_SYSCALL_BASE+206)
+#define __NR_fchown32			(__NR_SYSCALL_BASE+207)
+#define __NR_setresuid32		(__NR_SYSCALL_BASE+208)
+#define __NR_getresuid32		(__NR_SYSCALL_BASE+209)
+#define __NR_setresgid32		(__NR_SYSCALL_BASE+210)
+#define __NR_getresgid32		(__NR_SYSCALL_BASE+211)
+#define __NR_chown32			(__NR_SYSCALL_BASE+212)
+#define __NR_setuid32			(__NR_SYSCALL_BASE+213)
+#define __NR_setgid32			(__NR_SYSCALL_BASE+214)
+#define __NR_setfsuid32			(__NR_SYSCALL_BASE+215)
+#define __NR_setfsgid32			(__NR_SYSCALL_BASE+216)
 
 #define __sys2(x) #x
 #define __sys1(x) __sys2(x)
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/ipcbuf.h linux/include/asm-i386/ipcbuf.h
--- v2.3.38/linux/include/asm-i386/ipcbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/ipcbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,29 @@
+#ifndef __i386_IPCBUF_H__
+#define __i386_IPCBUF_H__
+
+/*
+ * The ipc64_perm structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm
+{
+	__kernel_key_t		key;
+	__kernel_uid32_t	uid;
+	__kernel_gid32_t	gid;
+	__kernel_uid32_t	cuid;
+	__kernel_gid32_t	cgid;
+	__kernel_mode_t		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+#endif /* __i386_IPCBUF_H__ */
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/msgbuf.h linux/include/asm-i386/msgbuf.h
--- v2.3.38/linux/include/asm-i386/msgbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/msgbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,31 @@
+#ifndef _I386_MSGBUF_H
+#define _I386_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	unsigned long	__unused1;
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	unsigned long	__unused2;
+	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long	__unused3;
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+#endif /* _I386_MSGBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h
--- v2.3.38/linux/include/asm-i386/posix_types.h	Sun Dec 27 10:39:50 1998
+++ linux/include/asm-i386/posix_types.h	Mon Jan 10 18:15:58 2000
@@ -24,6 +24,16 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef unsigned short	__kernel_uid16_t;
+typedef unsigned short	__kernel_gid16_t;
+typedef unsigned int	__kernel_uid32_t;
+typedef unsigned int	__kernel_gid32_t;
+
+#ifdef __KERNEL__
+#define UID16_COMPAT_NEEDED
+typedef unsigned short	__kernel_old_uid_t;
+typedef unsigned short	__kernel_old_gid_t;
+#endif /* __KERNEL__ */
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.3.38/linux/include/asm-i386/processor.h	Fri Jan  7 19:13:22 2000
+++ linux/include/asm-i386/processor.h	Mon Jan 10 18:29:07 2000
@@ -57,6 +57,7 @@
 #define X86_VENDOR_UMC 3
 #define X86_VENDOR_NEXGEN 4
 #define X86_VENDOR_CENTAUR 5
+#define X86_VENDOR_RISE 6
 #define X86_VENDOR_UNKNOWN 0xff
 
 /*
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/sembuf.h linux/include/asm-i386/sembuf.h
--- v2.3.38/linux/include/asm-i386/sembuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/sembuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,25 @@
+#ifndef _I386_SEMBUF_H
+#define _I386_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;		/* last semop time */
+	unsigned long	__unused1;
+	__kernel_time_t	sem_ctime;		/* last change time */
+	unsigned long	__unused2;
+	unsigned long	sem_nsems;		/* no. of semaphores in array */
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _I386_SEMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/shmbuf.h linux/include/asm-i386/shmbuf.h
--- v2.3.38/linux/include/asm-i386/shmbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/shmbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,42 @@
+#ifndef _I386_SHMBUF_H
+#define _I386_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for i386 architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	unsigned long		__unused1;
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	unsigned long		__unused2;
+	__kernel_time_t		shm_ctime;	/* last change time */
+	unsigned long		__unused3;
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused4;
+	unsigned long		__unused5;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _I386_SHMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h
--- v2.3.38/linux/include/asm-i386/siginfo.h	Wed Jul 28 10:30:10 1999
+++ linux/include/asm-i386/siginfo.h	Mon Jan 10 18:29:05 2000
@@ -24,7 +24,8 @@
 		/* kill() */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
+			uid_t _uid32;		/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
@@ -36,17 +37,19 @@
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
 			sigval_t _sigval;
+			uid_t _uid32;		/* sender's uid */
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
+			uid_t _uid32;		/* sender's uid */
 		} _sigchld;
 
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -62,11 +65,18 @@
 	} _sifields;
 } siginfo_t;
 
+#define UID16_SIGINFO_COMPAT_NEEDED
+
 /*
  * How these fields are to be accessed.
  */
 #define si_pid		_sifields._kill._pid
+#ifdef __KERNEL__
+#define si_uid		_sifields._kill._uid32
+#define si_uid16	_sifields._kill._uid
+#else
 #define si_uid		_sifields._kill._uid
+#endif /* __KERNEL__ */
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
diff -u --recursive --new-file v2.3.38/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h
--- v2.3.38/linux/include/asm-i386/unistd.h	Mon Dec 20 18:48:22 1999
+++ linux/include/asm-i386/unistd.h	Mon Jan 10 18:15:58 2000
@@ -202,6 +202,25 @@
 #define __NR_stat64		195
 #define __NR_lstat64		196
 #define __NR_fstat64		197
+#define __NR_lchown32		198
+#define __NR_getuid32		199
+#define __NR_getgid32		200
+#define __NR_geteuid32		201
+#define __NR_getegid32		202
+#define __NR_setreuid32		203
+#define __NR_setregid32		204
+#define __NR_getgroups32	205
+#define __NR_setgroups32	206
+#define __NR_fchown32		207
+#define __NR_setresuid32	208
+#define __NR_getresuid32	209
+#define __NR_setresgid32	210
+#define __NR_getresgid32	211
+#define __NR_chown32		212
+#define __NR_setuid32		213
+#define __NR_setgid32		214
+#define __NR_setfsuid32		215
+#define __NR_setfsgid32		216
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -u --recursive --new-file v2.3.38/linux/include/asm-m68k/ipcbuf.h linux/include/asm-m68k/ipcbuf.h
--- v2.3.38/linux/include/asm-m68k/ipcbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/ipcbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,29 @@
+#ifndef __m68k_IPCBUF_H__
+#define __m68k_IPCBUF_H__
+
+/*
+ * The user_ipc_perm structure for m68k architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm
+{
+	__kernel_key_t		key;
+	__kernel_uid32_t	uid;
+	__kernel_gid32_t	gid;
+	__kernel_uid32_t	cuid;
+	__kernel_gid32_t	cgid;
+	__kernel_mode_t		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	unsigned long		__unused1;
+	unsigned long		__unused2;
+};
+
+#endif /* __m68k_IPCBUF_H__ */
diff -u --recursive --new-file v2.3.38/linux/include/asm-m68k/msgbuf.h linux/include/asm-m68k/msgbuf.h
--- v2.3.38/linux/include/asm-m68k/msgbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/msgbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,31 @@
+#ifndef _M68K_MSGBUF_H
+#define _M68K_MSGBUF_H
+
+/* 
+ * The msqid64_ds structure for m68k architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+	struct ipc64_perm msg_perm;
+	__kernel_time_t msg_stime;	/* last msgsnd time */
+	unsigned long	__unused1;
+	__kernel_time_t msg_rtime;	/* last msgrcv time */
+	unsigned long	__unused2;
+	__kernel_time_t msg_ctime;	/* last change time */
+	unsigned long	__unused3;
+	unsigned long  msg_cbytes;	/* current number of bytes on queue */
+	unsigned long  msg_qnum;	/* number of messages in queue */
+	unsigned long  msg_qbytes;	/* max number of bytes on queue */
+	__kernel_pid_t msg_lspid;	/* pid of last msgsnd */
+	__kernel_pid_t msg_lrpid;	/* last receive pid */
+	unsigned long  __unused4;
+	unsigned long  __unused5;
+};
+
+#endif /* _M68K_MSGBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-m68k/posix_types.h linux/include/asm-m68k/posix_types.h
--- v2.3.38/linux/include/asm-m68k/posix_types.h	Mon Aug 10 11:02:24 1998
+++ linux/include/asm-m68k/posix_types.h	Mon Jan 10 18:15:58 2000
@@ -24,6 +24,16 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef unsigned short	__kernel_uid16_t;
+typedef unsigned short	__kernel_gid16_t;
+typedef unsigned int	__kernel_uid32_t;
+typedef unsigned int	__kernel_gid32_t;
+
+#ifdef __KERNEL__
+#define UID16_COMPAT_NEEDED
+typedef unsigned short	__kernel_old_uid_t;
+typedef unsigned short	__kernel_old_gid_t;
+#endif /* __KERNEL__ */
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
diff -u --recursive --new-file v2.3.38/linux/include/asm-m68k/sembuf.h linux/include/asm-m68k/sembuf.h
--- v2.3.38/linux/include/asm-m68k/sembuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sembuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,25 @@
+#ifndef _M68K_SEMBUF_H
+#define _M68K_SEMBUF_H
+
+/* 
+ * The semid64_ds structure for m68k architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+	struct ipc64_perm sem_perm;		/* permissions .. see ipc.h */
+	__kernel_time_t	sem_otime;		/* last semop time */
+	unsigned long	__unused1;
+	__kernel_time_t	sem_ctime;		/* last change time */
+	unsigned long	__unused2;
+	unsigned long	sem_nsems;		/* no. of semaphores in array */
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _M68K_SEMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-m68k/shmbuf.h linux/include/asm-m68k/shmbuf.h
--- v2.3.38/linux/include/asm-m68k/shmbuf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/shmbuf.h	Mon Jan 10 18:15:58 2000
@@ -0,0 +1,42 @@
+#ifndef _M68K_SHMBUF_H
+#define _M68K_SHMBUF_H
+
+/* 
+ * The shmid64_ds structure for m68k architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+	struct ipc64_perm	shm_perm;	/* operation perms */
+	size_t			shm_segsz;	/* size of segment (bytes) */
+	__kernel_time_t		shm_atime;	/* last attach time */
+	unsigned long		__unused1;
+	__kernel_time_t		shm_dtime;	/* last detach time */
+	unsigned long		__unused2;
+	__kernel_time_t		shm_ctime;	/* last change time */
+	unsigned long		__unused3;
+	__kernel_pid_t		shm_cpid;	/* pid of creator */
+	__kernel_pid_t		shm_lpid;	/* pid of last operator */
+	unsigned long		shm_nattch;	/* no. of current attaches */
+	unsigned long		__unused4;
+	unsigned long		__unused5;
+};
+
+struct shminfo64 {
+	unsigned long	shmmax;
+	unsigned long	shmmin;
+	unsigned long	shmmni;
+	unsigned long	shmseg;
+	unsigned long	shmall;
+	unsigned long	__unused1;
+	unsigned long	__unused2;
+	unsigned long	__unused3;
+	unsigned long	__unused4;
+};
+
+#endif /* _M68K_SHMBUF_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-m68k/siginfo.h linux/include/asm-m68k/siginfo.h
--- v2.3.38/linux/include/asm-m68k/siginfo.h	Wed Jul 28 10:30:10 1999
+++ linux/include/asm-m68k/siginfo.h	Mon Jan 10 18:15:58 2000
@@ -24,7 +24,8 @@
 		/* kill() */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
+			uid_t _uid32;		/* sender's uid */
 		} _kill;
 
 		/* POSIX.1b timers */
@@ -36,17 +37,19 @@
 		/* POSIX.1b signals */
 		struct {
 			pid_t _pid;		/* sender's pid */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
 			sigval_t _sigval;
+			uid_t _uid32;		/* sender's uid */
 		} _rt;
 
 		/* SIGCHLD */
 		struct {
 			pid_t _pid;		/* which child */
-			uid_t _uid;		/* sender's uid */
+			old_uid_t _uid;		/* backwards compatibility */
 			int _status;		/* exit code */
 			clock_t _utime;
 			clock_t _stime;
+			uid_t _uid32;		/* sender's uid */
 		} _sigchld;
 
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
@@ -62,11 +65,18 @@
 	} _sifields;
 } siginfo_t;
 
+#define UID16_SIGINFO_COMPAT_NEEDED
+
 /*
  * How these fields are to be accessed.
  */
 #define si_pid		_sifields._kill._pid
+#ifdef __KERNEL__
+#define si_uid		_sifields._kill._uid32
+#define si_uid16	_sifields._kill._uid
+#else
 #define si_uid		_sifields._kill._uid
+#endif /* __KERNEL__ */
 #define si_status	_sifields._sigchld._status
 #define si_utime	_sifields._sigchld._utime
 #define si_stime	_sifields._sigchld._stime
diff -u --recursive --new-file v2.3.38/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- v2.3.38/linux/include/asm-m68k/unistd.h	Mon Dec 20 18:48:22 1999
+++ linux/include/asm-m68k/unistd.h	Mon Jan 10 18:15:58 2000
@@ -201,6 +201,25 @@
 #define __NR_stat64		195
 #define __NR_lstat64		196
 #define __NR_fstat64		197
+#define __NR_chown32		198
+#define __NR_getuid32		199
+#define __NR_getgid32		200
+#define __NR_geteuid32		201
+#define __NR_getegid32		202
+#define __NR_setreuid32		203
+#define __NR_setregid32		204
+#define __NR_getgroups32	205
+#define __NR_setgroups32	206
+#define __NR_fchown32		207
+#define __NR_setresuid32	208
+#define __NR_getresuid32	209
+#define __NR_setresgid32	210
+#define __NR_getresgid32	211
+#define __NR_lchown32		212
+#define __NR_setuid32		213
+#define __NR_setgid32		214
+#define __NR_setfsuid32		215
+#define __NR_setfsgid32		216
 
 /* user-visible error numbers are in the range -1 - -122: see
    <asm-m68k/errno.h> */
diff -u --recursive --new-file v2.3.38/linux/include/asm-ppc/board.h linux/include/asm-ppc/board.h
--- v2.3.38/linux/include/asm-ppc/board.h	Tue Dec  7 09:32:50 1999
+++ linux/include/asm-ppc/board.h	Mon Jan 10 18:25:06 2000
@@ -27,6 +27,12 @@
 extern "C" {
 #endif
 
+/*
+ * The "residual" board information structure the boot loader passes
+ * into the kernel.
+ */
+
+extern unsigned char __res[];
 
 
 #ifdef __cplusplus
diff -u --recursive --new-file v2.3.38/linux/include/asm-ppc/hw_irq.h linux/include/asm-ppc/hw_irq.h
--- v2.3.38/linux/include/asm-ppc/hw_irq.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-ppc/hw_irq.h	Mon Jan 10 18:25:32 2000
@@ -34,7 +34,7 @@
 extern struct int_control_struct int_control;
 extern unsigned long timer_interrupt_intercept;
 extern unsigned long do_IRQ_intercept;
-void timer_interrupt(struct pt_regs *);
+int timer_interrupt(struct pt_regs *);
 
 extern void __no_use_sti(void);
 extern void __no_use_cli(void);
diff -u --recursive --new-file v2.3.38/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.3.38/linux/include/asm-ppc/irq.h	Sat Oct  9 11:47:50 1999
+++ linux/include/asm-ppc/irq.h	Mon Jan 10 18:25:06 2000
@@ -9,50 +9,47 @@
 extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
 
-#ifndef CONFIG_8xx
-
-#ifdef CONFIG_APUS
-#define enable_irq m68k_enable_irq
-#define disable_irq m68k_disable_irq
-#include <asm-m68k/irq.h>
-#undef enable_irq
-#undef disable_irq
-#else /* CONFIG_APUS */
+#if defined(CONFIG_4xx)
 
 /*
- * this is the # irq's for all ppc arch's (pmac/chrp/prep)
- * so it is the max of them all - which happens to be powermac
- * at present (G3 powermacs have 64).
+ * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
+ * 32 possible interrupts, a majority of which are not implemented on
+ * all cores. There are six configurable, external interrupt pins and
+ * there are eight internal interrupts for the on-chip serial port
+ * (SPU), DMA controller, and JTAG controller.
+ *
+ * The PowerPC 405 cores' Universal Interrupt Controller (UIC) has 32
+ * possible interrupts as well. There are seven, configurable external
+ * interrupt pins and there are 17 internal interrupts for the on-chip
+ * serial port, DMA controller, on-chip Ethernet controller, PCI, etc.
+ *
  */
-#define NR_IRQS			128
 
-#endif /* CONFIG_APUS */
+#define	NR_IRQS		32
 
-#define NUM_8259_INTERRUPTS	16
-#define IRQ_8259_CASCADE	16
-#define openpic_to_irq(n)	((n)+NUM_8259_INTERRUPTS)
-#define irq_to_openpic(n)	((n)-NUM_8259_INTERRUPTS)
+#define	AIC_INT0	(0)
+#define	AIC_INT4	(4)
+#define	AIC_INT5	(5)
+#define	AIC_INT6	(6)
+#define	AIC_INT7	(7)
+#define	AIC_INT8	(8)
+#define	AIC_INT9	(9)
+#define	AIC_INT10	(10)
+#define	AIC_INT11	(11)
+#define	AIC_INT27	(27)
+#define	AIC_INT28	(28)
+#define	AIC_INT29	(29)
+#define	AIC_INT30	(30)
+#define	AIC_INT31	(31)
 
-#ifndef CONFIG_APUS
-/*
- * This gets called from serial.c, which is now used on
- * powermacs as well as prep/chrp boxes.
- * Prep and chrp both have cascaded 8259 PICs.
- */
-static __inline__ int irq_cannonicalize(int irq)
+
+static __inline__ int
+irq_cannonicalize(int irq)
 {
-	if (ppc_md.irq_cannonicalize)
-	{
-		return ppc_md.irq_cannonicalize(irq);
-	}
-	else
-	{
-		return irq;
-	}
+	return (irq);
 }
-#endif
 
-#else /* CONFIG_8xx */
+#elif defined(CONFIG_8xx)
 
 /* The MPC8xx cores have 16 possible interrupts.  There are eight
  * possible level sensitive interrupts assigned and generated internally
@@ -120,6 +117,49 @@
 	return irq;
 }
 
-#endif /* CONFIG_8xx */
+#else
+
+#ifdef CONFIG_APUS
+#define enable_irq m68k_enable_irq
+#define disable_irq m68k_disable_irq
+#include <asm-m68k/irq.h>
+#undef enable_irq
+#undef disable_irq
+#else /* CONFIG_APUS */
+
+/*
+ * this is the # irq's for all ppc arch's (pmac/chrp/prep)
+ * so it is the max of them all - which happens to be powermac
+ * at present (G3 powermacs have 64).
+ */
+#define NR_IRQS			128
+
+#endif /* CONFIG_APUS */
+
+#define NUM_8259_INTERRUPTS	16
+#define IRQ_8259_CASCADE	16
+#define openpic_to_irq(n)	((n)+NUM_8259_INTERRUPTS)
+#define irq_to_openpic(n)	((n)-NUM_8259_INTERRUPTS)
+
+#ifndef CONFIG_APUS
+/*
+ * This gets called from serial.c, which is now used on
+ * powermacs as well as prep/chrp boxes.
+ * Prep and chrp both have cascaded 8259 PICs.
+ */
+static __inline__ int irq_cannonicalize(int irq)
+{
+	if (ppc_md.irq_cannonicalize)
+	{
+		return ppc_md.irq_cannonicalize(irq);
+	}
+	else
+	{
+		return irq;
+	}
+}
+#endif /* !CONFIG_APUS */
 
 #endif
+
+#endif /* _ASM_IRQ_H */
diff -u --recursive --new-file v2.3.38/linux/include/asm-ppc/oak.h linux/include/asm-ppc/oak.h
--- v2.3.38/linux/include/asm-ppc/oak.h	Tue Dec  7 09:32:51 1999
+++ linux/include/asm-ppc/oak.h	Mon Jan 10 18:25:32 2000
@@ -14,6 +14,8 @@
 #ifndef	__OAK_H__
 #define	__OAK_H__
 
+#include <asm/irq.h>
+
 
 #ifdef __cplusplus
 extern "C" {
@@ -22,6 +24,41 @@
 #define _IO_BASE	0
 #define _ISA_MEM_BASE	0
 #define PCI_DRAM_OFFSET	0
+
+/* Memory map for the "Oak" evaluation board */
+
+#define	PPC403SPU_IO_BASE      	0x40000000	/* 403 On-chip serial port */
+#define	PPC403SPU_IO_SIZE      	0x00000008
+#define	OAKSERIAL_IO_BASE	0x7E000000	/* NS16550DV serial port */
+#define	OAKSERIAL_IO_SIZE	0x00000008
+#define	OAKNET_IO_BASE		0xF4000000	/* NS83902AV Ethernet */
+#define	OAKNET_IO_SIZE		0x00000040
+#define	OAKPROM_IO_BASE		0xFFFE0000	/* AMD 29F010 Flash ROM */
+#define	OAKPROM_IO_SIZE		0x00020000
+
+
+/* Interrupt assignments fixed by the hardware implementation */
+
+#define	PPC403SPU_RX_INT	AIC_INT4
+#define	PPC403SPU_TX_INT	AIC_INT5
+#define	OAKNET_INT		AIC_INT27
+#define	OAKSERIAL_INT		AIC_INT28
+
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Oak" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* Bus speed, in Hz */
+} bd_t;
 
 
 #ifdef __cplusplus
diff -u --recursive --new-file v2.3.38/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.3.38/linux/include/asm-ppc/pgtable.h	Tue Dec  7 09:32:51 1999
+++ linux/include/asm-ppc/pgtable.h	Mon Jan 10 18:25:06 2000
@@ -4,20 +4,21 @@
 #include <linux/config.h>
 
 #ifndef __ASSEMBLY__
+#include <linux/sched.h>
 #include <linux/threads.h>
 #include <asm/processor.h>		/* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
 
-#ifndef CONFIG_8xx
-struct mm_struct;
-struct vm_area_struct;
+#if defined(CONFIG_4xx)
 extern void local_flush_tlb_all(void);
 extern void local_flush_tlb_mm(struct mm_struct *mm);
 extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
-			    unsigned long end);
-#else /* CONFIG_8xx */
+                           unsigned long end);
+extern inline void flush_hash_page(unsigned context, unsigned long va)
+	{ }
+#elif defined(CONFIG_8xx)
 #define __tlbia()	asm volatile ("tlbia" : : )
 
 extern inline void local_flush_tlb_all(void)
@@ -32,6 +33,14 @@
 	{ __tlbia(); }
 extern inline void flush_hash_page(unsigned context, unsigned long va)
 	{ }
+#else
+struct mm_struct;
+struct vm_area_struct;
+extern void local_flush_tlb_all(void);
+extern void local_flush_tlb_mm(struct mm_struct *mm);
+extern void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+			    unsigned long end);
 #endif
 
 #define flush_tlb_all local_flush_tlb_all
@@ -148,8 +157,59 @@
  * Bits in a linux-style PTE.  These match the bits in the
  * (hardware-defined) PowerPC PTE as closely as possible.
  */
-#ifndef CONFIG_8xx
-/* Definitions for 60x, 740/750, etc. */
+
+#if defined(CONFIG_4xx)
+/*
+ * At present, all PowerPC 400-class processors share a similar TLB
+ * architecture. The instruction and data sides share a unified, 64-entry,
+ * fully-associative TLB which is maintained under software control. In
+ * addition, the instruction side has a hardware-managed, 4-entry, fully-
+ * associative TLB which serves as a first level to the shared TLB. These
+ * two TLBs are known as the UTLB and ITLB, respectively.
+ */
+
+#define        PPC4XX_TLB_SIZE 64
+
+/*
+ * TLB entries are defined by a "high" tag portion and a "low" data portion.
+ * On all architectures, the data portion is 32-bits.
+ */
+
+#define	TLB_LO          1
+#define	TLB_HI          0
+       
+#define	TLB_DATA        TLB_LO
+#define	TLB_TAG         TLB_HI
+
+/* Tag portion */
+
+#define TLB_EPN_MASK    0xFFFFFC00      /* Effective Page Number */
+#define TLB_PAGESZ_MASK 0x00000380
+#define TLB_PAGESZ(x)   (((x) & 0x7) << 7)
+#define   PAGESZ_1K		0
+#define   PAGESZ_4K             1
+#define   PAGESZ_16K            2
+#define   PAGESZ_64K            3
+#define   PAGESZ_256K           4
+#define   PAGESZ_1M             5
+#define   PAGESZ_4M             6
+#define   PAGESZ_16M            7
+#define TLB_VALID       0x00000040      /* Entry is valid */
+
+/* Data portion */
+                 
+#define TLB_RPN_MASK    0xFFFFFC00      /* Real Page Number */
+#define TLB_PERM_MASK   0x00000300
+#define TLB_EX          0x00000200      /* Instruction execution allowed */
+#define TLB_WR          0x00000100      /* Writes permitted */
+#define TLB_ZSEL_MASK   0x000000F0
+#define TLB_ZSEL(x)     (((x) & 0xF) << 4)
+#define TLB_ATTR_MASK   0x0000000F
+#define TLB_W           0x00000008      /* Caching is write-through */
+#define TLB_I           0x00000004      /* Caching is inhibited */
+#define TLB_M           0x00000002      /* Memory is coherent */
+#define TLB_G           0x00000001      /* Memory is guarded from prefetch */
+
 #define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
 #define _PAGE_USER	0x002	/* matches one of the PP bits */
 #define _PAGE_RW	0x004	/* software: user write access allowed */
@@ -160,9 +220,8 @@
 #define _PAGE_DIRTY	0x080	/* C: page changed */
 #define _PAGE_ACCESSED	0x100	/* R: page referenced */
 #define _PAGE_HWWRITE	0x200	/* software: _PAGE_RW & _PAGE_DIRTY */
-#define _PAGE_SHARED	0
-
-#else
+#define	_PAGE_SHARED	0
+#elif defined(CONFIG_8xx)
 /* Definitions for 8xx embedded chips. */
 #define _PAGE_PRESENT	0x0001	/* Page is valid */
 #define _PAGE_NO_CACHE	0x0002	/* I: cache inhibit */
@@ -183,8 +242,20 @@
  * protection.
  */
 #define _PAGE_HWWRITE	_PAGE_DIRTY
-
-#endif /* CONFIG_8xx */
+#else
+/* Definitions for 60x, 740/750, etc. */
+#define _PAGE_PRESENT	0x001	/* software: pte contains a translation */
+#define _PAGE_USER	0x002	/* matches one of the PP bits */
+#define _PAGE_RW	0x004	/* software: user write access allowed */
+#define _PAGE_GUARDED	0x008
+#define _PAGE_COHERENT	0x010	/* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE	0x020	/* I: cache inhibit */
+#define _PAGE_WRITETHRU	0x040	/* W: cache write-through */
+#define _PAGE_DIRTY	0x080	/* C: page changed */
+#define _PAGE_ACCESSED	0x100	/* R: page referenced */
+#define _PAGE_HWWRITE	0x200	/* software: _PAGE_RW & _PAGE_DIRTY */
+#define _PAGE_SHARED	0
+#endif
 
 #define _PAGE_CHG_MASK	(PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
diff -u --recursive --new-file v2.3.38/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.3.38/linux/include/asm-ppc/processor.h	Fri Jan  7 19:13:22 2000
+++ linux/include/asm-ppc/processor.h	Mon Jan 10 18:25:32 2000
@@ -12,28 +12,34 @@
 #include <asm/ptrace.h>
 #include <asm/residual.h>
 
-/* Bit encodings for Machine State Register (MSR) */
+/* Machine State Register (MSR) Fields */
+
 #ifdef CONFIG_PPC64
 #define MSR_SF		(1<<63)
 #define MSR_ISF		(1<<61)
-#endif /* CONFIG_PPC64 */
+#endif /* CONFIG_PPC64 */   
 #define MSR_VEC		(1<<25)		/* Enable AltiVec */
 #define MSR_POW		(1<<18)		/* Enable Power Management */
+#define MSR_WE		(1<<18)		/* Wait State Enable */
 #define MSR_TGPR	(1<<17)		/* TLB Update registers in use */
-#define MSR_ILE		(1<<16)		/* Interrupt Little-Endian enable */
-#define MSR_EE		(1<<15)		/* External Interrupt enable */
-#define MSR_PR		(1<<14)		/* Supervisor/User privilege */
+#define MSR_CE		(1<<17)		/* Critical Interrupt Enable */
+#define MSR_ILE		(1<<16)		/* Interrupt Little Endian */
+#define MSR_EE		(1<<15)		/* External Interrupt Enable */
+#define MSR_PR		(1<<14)		/* Problem State / Privilege Level */
 #define MSR_FP		(1<<13)		/* Floating Point enable */
-#define MSR_ME		(1<<12)		/* Machine Check enable */
+#define MSR_ME		(1<<12)		/* Machine Check Enable */
 #define MSR_FE0		(1<<11)		/* Floating Exception mode 0 */
 #define MSR_SE		(1<<10)		/* Single Step */
 #define MSR_BE		(1<<9)		/* Branch Trace */
+#define MSR_DE		(1<<9) 		/* Debug Exception Enable */
 #define MSR_FE1		(1<<8)		/* Floating Exception mode 1 */
 #define MSR_IP		(1<<6)		/* Exception prefix 0x000/0xFFF */
-#define MSR_IR		(1<<5)		/* Instruction MMU enable */
-#define MSR_DR		(1<<4)		/* Data MMU enable */
+#define MSR_IR		(1<<5) 		/* Instruction Relocate */
+#define MSR_DR		(1<<4) 		/* Data Relocate */
+#define MSR_PE		(1<<3)		/* Protection Enable */
+#define MSR_PX		(1<<2)		/* Protection Exclusive Mode */
 #define MSR_RI		(1<<1)		/* Recoverable Exception */
-#define MSR_LE		(1<<0)		/* Little-Endian enable */
+#define MSR_LE		(1<<0) 		/* Little Endian */
 
 #ifdef CONFIG_APUS_FAST_EXCEPT
 #define MSR_		MSR_ME|MSR_IP|MSR_RI
@@ -43,30 +49,8 @@
 #define MSR_KERNEL      MSR_|MSR_IR|MSR_DR
 #define MSR_USER	MSR_KERNEL|MSR_PR|MSR_EE
 
-/* Bit encodings for Hardware Implementation Register (HID0)
-   on PowerPC 603, 604, etc. processors (not 601). */
-#define HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
-#define HID0_EBA	(1<<29)		/* Enable Bus Address Parity */
-#define HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
-#define HID0_SBCLK	(1<<27)
-#define HID0_EICE	(1<<26)
-#define HID0_ECLK	(1<<25)
-#define HID0_PAR	(1<<24)
-#define HID0_DOZE	(1<<23)
-#define HID0_NAP	(1<<22)
-#define HID0_SLEEP	(1<<21)
-#define HID0_DPM	(1<<20)
-#define HID0_ICE	(1<<15)		/* Instruction Cache Enable */
-#define HID0_DCE	(1<<14)		/* Data Cache Enable */
-#define HID0_ILOCK	(1<<13)		/* Instruction Cache Lock */
-#define HID0_DLOCK	(1<<12)		/* Data Cache Lock */
-#define HID0_ICFI	(1<<11)		/* Instruction Cache Flash Invalidate */
-#define HID0_DCI	(1<<10)		/* Data Cache Invalidate */
-#define HID0_SIED	(1<<7)		/* Serial Instruction Execution [Disable] */
-#define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
-#define HID0_BTCD	(1<<1)		/* Branch target cache disable */
+/* Floating Point Status and Control Register (FPSCR) Fields */
 
-/* fpscr settings */
 #define FPSCR_FX	0x80000000	/* FPU exception summary */
 #define FPSCR_FEX	0x40000000	/* FPU enabled exception summary */
 #define FPSCR_VX	0x20000000	/* Invalid operation summary */
@@ -95,17 +79,418 @@
 #define FPSCR_NI	0x00000004	/* FPU non IEEE-Mode */
 #define FPSCR_RN	0x00000003	/* FPU rounding control */
 
-#define _MACH_prep     1
-#define _MACH_Pmac     2  /* pmac or pmac clone (non-chrp) */
-#define _MACH_chrp     4  /* chrp machine */
-#define _MACH_mbx      8  /* Motorola MBX board */
-#define _MACH_apus    16  /* amiga with phase5 powerup */
-#define _MACH_fads    32  /* Motorola FADS board */
-#define _MACH_rpxlite 64  /* RPCG RPX-Lite 8xx board */
-#define _MACH_bseip   128 /* Bright Star Engineering ip-Engine */
-#define _MACH_yk      256 /* Motorola Yellowknife */
-#define _MACH_gemini  512 /* Synergy Microsystems gemini board */
-#define _MACH_classic 1024  /* RPCG RPX-Classic 8xx board */
+/* Special Purpose Registers (SPRNs)*/
+
+#define	SPRN_CDBCR	0x3D7	/* Cache Debug Control Register */
+#define	SPRN_CTR	0x009	/* Count Register */
+#define	SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
+#define	SPRN_DAC1	0x3F6	/* Data Address Compare 1 */
+#define	SPRN_DAC2	0x3F7	/* Data Address Compare 2 */
+#define	SPRN_DAR	0x013	/* Data Address Register */
+#define	SPRN_DBAT0L	0x219	/* Data BAT 0 Lower Register */
+#define	SPRN_DBAT0U	0x218	/* Data BAT 0 Upper Register */
+#define	SPRN_DBAT1L	0x21B	/* Data BAT 1 Lower Register */
+#define	SPRN_DBAT1U	0x21A	/* Data BAT 1 Upper Register */
+#define	SPRN_DBAT2L	0x21D	/* Data BAT 2 Lower Register */
+#define	SPRN_DBAT2U	0x21C	/* Data BAT 2 Upper Register */
+#define	SPRN_DBAT3L	0x21F	/* Data BAT 3 Lower Register */
+#define	SPRN_DBAT3U	0x21E	/* Data BAT 3 Upper Register */
+#define	SPRN_DBCR	0x3F2	/* Debug Control Regsiter */
+#define	  DBCR_EDM	0x80000000
+#define	  DBCR_IDM	0x40000000
+#define	  DBCR_RST(x)	(((x) & 0x3) << 28)
+#define	    NONE       	0
+#define	    CORE       	1
+#define	    CHIP       	2
+#define	    SYSTEM	3
+#define	  DBCR_IC	0x08000000	/* Instruction Completion Debug Evnt */
+#define	  DBCR_BT	0x04000000	/* Branch Taken Debug Event */
+#define	  DBCR_EDE	0x02000000	/* Exception Debug Event */
+#define	  DBCR_TDE	0x01000000	/* TRAP Debug Event */
+#define	  DBCR_FER	0x00F80000	/* First Events Remaining Mask */
+#define	  DBCR_FT	0x00040000	/* Freeze Timers on Debug Event */
+#define	  DBCR_IA1	0x00020000	/* Instr. Addr. Compare 1 Enable */
+#define	  DBCR_IA2	0x00010000	/* Instr. Addr. Compare 2 Enable */
+#define	  DBCR_D1R	0x00008000	/* Data Addr. Compare 1 Read Enable */
+#define	  DBCR_D1W	0x00004000	/* Data Addr. Compare 1 Write Enable */
+#define	  DBCR_D1S(x)	(((x) & 0x3) << 12)	/* Data Adrr. Compare 1 Size */
+#define	    DAC_BYTE	0
+#define	    DAC_HALF	1
+#define	    DAC_WORD	2
+#define	    DAC_QUAD	3
+#define	  DBCR_D2R	0x00000800	/* Data Addr. Compare 2 Read Enable */
+#define	  DBCR_D2W	0x00000400	/* Data Addr. Compare 2 Write Enable */
+#define	  DBCR_D2S(x)	(((x) & 0x3) << 8)	/* Data Addr. Compare 2 Size */
+#define	  DBCR_SBT	0x00000040	/* Second Branch Taken Debug Event */
+#define	  DBCR_SED	0x00000020	/* Second Exception Debug Event */
+#define	  DBCR_STD	0x00000010	/* Second Trap Debug Event */
+#define	  DBCR_SIA	0x00000008	/* Second IAC Enable */
+#define	  DBCR_SDA	0x00000004	/* Second DAC Enable */
+#define	  DBCR_JOI	0x00000002	/* JTAG Serial Outbound Int. Enable */
+#define	  DBCR_JII	0x00000001	/* JTAG Serial Inbound Int. Enable */
+#define	SPRN_DBCR0	0x3F2	/* Debug Control Register 0 */
+#define	SPRN_DBCR1	0x3BD	/* Debug Control Register 1 */
+#define	SPRN_DBSR	0x3F0	/* Debug Status Register */
+#define	SPRN_DCCR	0x3FA	/* Data Cache Cacheability Register */
+#define	  DCCR_NOCACHE		0	/* Noncacheable */
+#define	  DCCR_CACHE		1	/* Cacheable */
+#define	SPRN_DCMP	0x3D1	/* Data TLB Compare Register */
+#define	SPRN_DCWR	0x3BA	/* Data Cache Write-thru Register */
+#define	  DCWR_COPY		0	/* Copy-back */
+#define	  DCWR_WRITE		1	/* Write-through */
+#define	SPRN_DEAR	0x3D5	/* Data Error Address Register */
+#define	SPRN_DEC	0x016	/* Decrement Register */
+#define	SPRN_DMISS	0x3D0	/* Data TLB Miss Register */
+#define	SPRN_DSISR	0x012	/* Data Storage Interrupt Status Register */
+#define	SPRN_EAR	0x11A	/* External Address Register */
+#define	SPRN_ESR	0x3D4	/* Exception Syndrome Register */
+#define	  ESR_IMCP	0x80000000	/* Instr. Machine Check - Protection */
+#define	  ESR_IMCN	0x40000000	/* Instr. Machine Check - Non-config */
+#define	  ESR_IMCB	0x20000000	/* Instr. Machine Check - Bus error */
+#define	  ESR_IMCT	0x10000000	/* Instr. Machine Check - Timeout */
+#define	  ESR_PIL	0x08000000	/* Program Exception - Illegal */
+#define	  ESR_PPR	0x04000000	/* Program Exception - Priveleged */
+#define	  ESR_PTR	0x02000000	/* Program Exception - Trap */
+#define	  ESR_DST	0x00800000	/* Storage Exception - Data miss */
+#define	  ESR_DIZ	0x00400000	/* Storage Exception - Zone fault */
+#define	SPRN_EVPR	0x3D6	/* Exception Vector Prefix Register */
+#define	SPRN_HASH1	0x3D2	/* Primary Hash Address Register */
+#define	SPRN_HASH2	0x3D3	/* Secondary Hash Address Resgister */
+#define	SPRN_HID0	0x3F0	/* Hardware Implementation Register 0 */
+#define	  HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
+#define	  HID0_EBA	(1<<29)		/* Enable Bus Address Parity */
+#define	  HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
+#define	  HID0_SBCLK	(1<<27)
+#define	  HID0_EICE	(1<<26)
+#define	  HID0_ECLK	(1<<25)
+#define	  HID0_PAR	(1<<24)
+#define	  HID0_DOZE	(1<<23)
+#define	  HID0_NAP	(1<<22)
+#define	  HID0_SLEEP	(1<<21)
+#define	  HID0_DPM	(1<<20)
+#define	  HID0_ICE	(1<<15)		/* Instruction Cache Enable */
+#define	  HID0_DCE	(1<<14)		/* Data Cache Enable */
+#define	  HID0_ILOCK	(1<<13)		/* Instruction Cache Lock */
+#define	  HID0_DLOCK	(1<<12)		/* Data Cache Lock */
+#define	  HID0_ICFI	(1<<11)		/* Instr. Cache Flash Invalidate */
+#define	  HID0_DCI	(1<<10)		/* Data Cache Invalidate */
+#define	  HID0_SIED	(1<<7)		/* Serial Instr. Execution [Disable] */
+#define	  HID0_BHTE	(1<<2)		/* Branch History Table Enable */
+#define	  HID0_BTCD	(1<<1)		/* Branch target cache disable */
+#define	SPRN_HID1	0x3F1	/* Hardware Implementation Register 1 */
+#define	SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
+#define	SPRN_IAC1	0x3F4	/* Instruction Address Compare 1 */
+#define	SPRN_IAC2	0x3F5	/* Instruction Address Compare 2 */
+#define	SPRN_IBAT0L	0x211	/* Instruction BAT 0 Lower Register */
+#define	SPRN_IBAT0U	0x210	/* Instruction BAT 0 Upper Register */
+#define	SPRN_IBAT1L	0x213	/* Instruction BAT 1 Lower Register */
+#define	SPRN_IBAT1U	0x212	/* Instruction BAT 1 Upper Register */
+#define	SPRN_IBAT2L	0x215	/* Instruction BAT 2 Lower Register */
+#define	SPRN_IBAT2U	0x214	/* Instruction BAT 2 Upper Register */
+#define	SPRN_IBAT3L	0x217	/* Instruction BAT 3 Lower Register */
+#define	SPRN_IBAT3U	0x216	/* Instruction BAT 3 Upper Register */
+#define	SPRN_ICCR	0x3FB	/* Instruction Cache Cacheability Register */
+#define	  ICCR_NOCACHE		0	/* Noncacheable */
+#define	  ICCR_CACHE		1	/* Cacheable */
+#define	SPRN_ICDBDR	0x3D3	/* Instruction Cache Debug Data Register */
+#define	SPRN_ICMP	0x3D5	/* Instruction TLB Compare Register */
+#define	SPRN_ICTC	0x3FB	/* Instruction Cache Throttling Control Reg */
+#define	SPRN_IMISS	0x3D4	/* Instruction TLB Miss Register */
+#define	SPRN_IMMR	0x27E  	/* Internal Memory Map Register */
+#define	SPRN_L2CR	0x3F9	/* Level 2 Cache Control Regsiter */
+#define	SPRN_LR		0x008	/* Link Register */
+#define	SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 */
+#define	SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 */
+#define	SPRN_PBL1	0x3FC	/* Protection Bound Lower 1 */
+#define	SPRN_PBL2	0x3FE	/* Protection Bound Lower 2 */
+#define	SPRN_PBU1	0x3FD	/* Protection Bound Upper 1 */
+#define	SPRN_PBU2	0x3FF	/* Protection Bound Upper 2 */
+#define	SPRN_PID	0x3B1	/* Process ID */
+#define	SPRN_PIR	0x3FF	/* Processor Identification Register */
+#define	SPRN_PIT	0x3DB	/* Programmable Interval Timer */
+#define	SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
+#define	SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
+#define	SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
+#define	SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
+#define	SPRN_PVR	0x11F	/* Processor Version Register */
+#define	SPRN_RPA	0x3D6	/* Required Physical Address Register */
+#define	SPRN_SDA	0x3BF	/* Sampled Data Address Register */
+#define	SPRN_SDR1	0x019	/* MMU Hash Base Register */
+#define	SPRN_SGR	0x3B9	/* Storage Guarded Register */
+#define	  SGR_NORMAL		0
+#define	  SGR_GUARDED		1
+#define	SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
+#define	SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
+#define	SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
+#define	SPRN_SPRG2	0x112	/* Special Purpose Register General 2 */
+#define	SPRN_SPRG3	0x113	/* Special Purpose Register General 3 */
+#define	SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
+#define	SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
+#define	SPRN_SRR2	0x3DE	/* Save/Restore Register 2 */
+#define	SPRN_SRR3 	0x3DF	/* Save/Restore Register 3 */
+#define	SPRN_TBHI	0x3DC	/* Time Base High */
+#define	SPRN_TBHU	0x3CC	/* Time Base High User-mode */
+#define	SPRN_TBLO	0x3DD	/* Time Base Low */
+#define	SPRN_TBLU	0x3CD	/* Time Base Low User-mode */
+#define	SPRN_TBRL	0x10D	/* Time Base Read Lower Register */
+#define	SPRN_TBRU	0x10C	/* Time Base Read Upper Register */
+#define	SPRN_TBWL	0x11D	/* Time Base Write Lower Register */
+#define	SPRN_TBWU	0x11C	/* Time Base Write Upper Register */
+#define	SPRN_TCR	0x3DA	/* Timer Control Register */
+#define	  TCR_WP(x)		(((x)&0x3)<<30)	/* WDT Period */
+#define	    WP_2_17		0		/* 2^17 clocks */
+#define	    WP_2_21		1		/* 2^21 clocks */
+#define	    WP_2_25		2		/* 2^25 clocks */
+#define	    WP_2_29		3		/* 2^29 clocks */
+#define	  TCR_WRC(x)		(((x)&0x3)<<28)	/* WDT Reset Control */
+#define	    WRC_NONE		0		/* No reset will occur */
+#define	    WRC_CORE		1		/* Core reset will occur */
+#define	    WRC_CHIP		2		/* Chip reset will occur */
+#define	    WRC_SYSTEM		3		/* System reset will occur */
+#define	  TCR_WIE		0x08000000	/* WDT Interrupt Enable */
+#define	  TCR_PIE		0x04000000	/* PIT Interrupt Enable */
+#define	  TCR_FP(x)		(((x)&0x3)<<24)	/* FIT Period */
+#define	    FP_2_9		0		/* 2^9 clocks */
+#define	    FP_2_13		1		/* 2^13 clocks */
+#define	    FP_2_17		2		/* 2^17 clocks */
+#define	    FP_2_21		3		/* 2^21 clocks */
+#define	  TCR_FIE		0x00800000	/* FIT Interrupt Enable */
+#define	  TCR_ARE		0x00400000	/* Auto Reload Enable */
+#define	SPRN_THRM1	0x3FC	/* Thermal Management Register 1 */
+#define	  THRM1_TIN		(1<<0)
+#define	  THRM1_TIV		(1<<1)
+#define	  THRM1_THRES		(0x7f<<2)
+#define	  THRM1_TID		(1<<29)
+#define	  THRM1_TIE		(1<<30)
+#define	  THRM1_V		(1<<31)
+#define	SPRN_THRM2	0x3FD	/* Thermal Management Register 2 */
+#define	SPRN_THRM3	0x3FE	/* Thermal Management Register 3 */
+#define	  THRM3_E		(1<<31)
+#define	SPRN_TSR	0x3D8	/* Timer Status Register */
+#define	  TSR_ENW		0x80000000	/* Enable Next Watchdog */
+#define	  TSR_WIS		0x40000000	/* WDT Interrupt Status */
+#define	  TSR_WRS(x)		(((x)&0x3)<<28)	/* WDT Reset Status */
+#define	    WRS_NONE		0		/* No WDT reset occurred */
+#define	    WRS_CORE		1		/* WDT forced core reset */
+#define	    WRS_CHIP		2		/* WDT forced chip reset */
+#define	    WRS_SYSTEM		3		/* WDT forced system reset */
+#define	  TSR_PIS		0x08000000	/* PIT Interrupt Status */
+#define	  TSR_FIS		0x04000000	/* FIT Interrupt Status */
+#define	SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 */
+#define	SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 */
+#define	SPRN_UPMC1	0x3A9	/* User Performance Counter Register 1 */
+#define	SPRN_UPMC2	0x3AA	/* User Performance Counter Register 2 */
+#define	SPRN_UPMC3	0x3AD	/* User Performance Counter Register 3 */
+#define	SPRN_UPMC4	0x3AE	/* User Performance Counter Register 4 */
+#define	SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register */
+#define	SPRN_XER	0x001	/* Fixed Point Exception Register */
+#define	SPRN_ZPR	0x3B0	/* Zone Protection Register */
+
+/* Short-hand versions for a number of the above SPRNs */
+
+#define	CTR	SPRN_CTR	/* Counter Register */
+#define	DAR	SPRN_DAR	/* Data Address Register */
+#define	DABR	SPRN_DABR	/* Data Address Breakpoint Register */
+#define	DBAT0L	SPRN_DBAT0L	/* Data BAT 0 Lower Register */
+#define	DBAT0U	SPRN_DBAT0U	/* Data BAT 0 Upper Register */
+#define	DBAT1L	SPRN_DBAT1L	/* Data BAT 1 Lower Register */
+#define	DBAT1U	SPRN_DBAT1U	/* Data BAT 1 Upper Register */
+#define	DBAT2L	SPRN_DBAT2L	/* Data BAT 2 Lower Register */
+#define	DBAT2U	SPRN_DBAT2U	/* Data BAT 2 Upper Register */
+#define	DBAT3L	SPRN_DBAT3L	/* Data BAT 3 Lower Register */
+#define	DBAT3U	SPRN_DBAT3U	/* Data BAT 3 Upper Register */
+#define	DCMP	SPRN_DCMP      	/* Data TLB Compare Register */
+#define	DEC	SPRN_DEC       	/* Decrement Register */
+#define	DMISS	SPRN_DMISS     	/* Data TLB Miss Register */
+#define	DSISR	SPRN_DSISR	/* Data Storage Interrupt Status Register */
+#define	EAR	SPRN_EAR       	/* External Address Register */
+#define	HASH1	SPRN_HASH1	/* Primary Hash Address Register */
+#define	HASH2	SPRN_HASH2	/* Secondary Hash Address Register */
+#define	HID0	SPRN_HID0	/* Hardware Implementation Register 0 */
+#define	HID1	SPRN_HID1	/* Hardware Implementation Register 1 */
+#define	IABR	SPRN_IABR      	/* Instruction Address Breakpoint Register */
+#define	IBAT0L	SPRN_IBAT0L	/* Instruction BAT 0 Lower Register */
+#define	IBAT0U	SPRN_IBAT0U	/* Instruction BAT 0 Upper Register */
+#define	IBAT1L	SPRN_IBAT1L	/* Instruction BAT 1 Lower Register */
+#define	IBAT1U	SPRN_IBAT1U	/* Instruction BAT 1 Upper Register */
+#define	IBAT2L	SPRN_IBAT2L	/* Instruction BAT 2 Lower Register */
+#define	IBAT2U	SPRN_IBAT2U	/* Instruction BAT 2 Upper Register */
+#define	IBAT3L	SPRN_IBAT3L	/* Instruction BAT 3 Lower Register */
+#define	IBAT3U	SPRN_IBAT3U	/* Instruction BAT 3 Upper Register */
+#define	ICMP	SPRN_ICMP	/* Instruction TLB Compare Register */
+#define	IMISS	SPRN_IMISS	/* Instruction TLB Miss Register */
+#define	IMMR	SPRN_IMMR      	/* PPC 860/821 Internal Memory Map Register */
+#define	L2CR	SPRN_L2CR    	/* PPC 750 L2 control register */
+#define	LR	SPRN_LR
+#define	PVR	SPRN_PVR	/* Processor Version */
+#define	RPA	SPRN_RPA	/* Required Physical Address Register */
+#define	SDR1	SPRN_SDR1      	/* MMU hash base register */
+#define	SPR0	SPRN_SPRG0	/* Supervisor Private Registers */
+#define	SPR1	SPRN_SPRG1
+#define	SPR2	SPRN_SPRG2
+#define	SPR3	SPRN_SPRG3
+#define	SPRG0   SPRN_SPRG0
+#define	SPRG1   SPRN_SPRG1
+#define	SPRG2   SPRN_SPRG2
+#define	SPRG3   SPRN_SPRG3
+#define	SRR0	SPRN_SRR0	/* Save and Restore Register 0 */
+#define	SRR1	SPRN_SRR1	/* Save and Restore Register 1 */
+#define	TBRL	SPRN_TBRL	/* Time Base Read Lower Register */
+#define	TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
+#define	TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
+#define	TBWU	SPRN_TBWU	/* Time Base Write Upper Register */
+#define	THRM1	SPRN_THRM1	/* Thermal Management Register 1 */
+#define	THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
+#define	THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
+#define	XER	SPRN_XER
+
+
+/* Device Control Registers */
+
+#define	DCRN_BEAR	0x090	/* Bus Error Address Register */
+#define	DCRN_BESR	0x091	/* Bus Error Syndrome Register */
+#define	  BESR_DSES    	0x80000000	/* Data-Side Error Status */
+#define	  BESR_DMES	0x40000000	/* DMA Error Status */
+#define	  BESR_RWS	0x20000000	/* Read/Write Status */
+#define	  BESR_ETMASK	0x1C000000	/* Error Type */
+#define	    ET_PROT	0
+#define	    ET_PARITY	1
+#define	    ET_NCFG	2
+#define	    ET_BUSERR	4
+#define	    ET_BUSTO	6
+#define	DCRN_DMACC0	0x0C4	/* DMA Chained Count Register 0 */
+#define	DCRN_DMACC1	0x0CC	/* DMA Chained Count Register 1 */
+#define	DCRN_DMACC2	0x0D4	/* DMA Chained Count Register 2 */
+#define	DCRN_DMACC3	0x0DC    /* DMA Chained Count Register 3 */
+#define	DCRN_DMACR0	0x0C0    /* DMA Channel Control Register 0 */
+#define	DCRN_DMACR1	0x0C8    /* DMA Channel Control Register 1 */
+#define	DCRN_DMACR2	0x0D0    /* DMA Channel Control Register 2 */
+#define	DCRN_DMACR3	0x0D8    /* DMA Channel Control Register 3 */
+#define	DCRN_DMACT0	0x0C1    /* DMA Count Register 0 */
+#define	DCRN_DMACT1	0x0C9    /* DMA Count Register 1 */
+#define	DCRN_DMACT2	0x0D1    /* DMA Count Register 2 */
+#define	DCRN_DMACT3	0x0D9    /* DMA Count Register 3 */
+#define	DCRN_DMADA0	0x0C2    /* DMA Destination Address Register 0 */
+#define	DCRN_DMADA1	0x0CA    /* DMA Destination Address Register 1 */
+#define	DCRN_DMADA2	0x0D2    /* DMA Destination Address Register 2 */
+#define	DCRN_DMADA3	0x0DA    /* DMA Destination Address Register 3 */
+#define	DCRN_DMASA0	0x0C3    /* DMA Source Address Register 0 */
+#define	DCRN_DMASA1	0x0CB    /* DMA Source Address Register 1 */
+#define	DCRN_DMASA2	0x0D3    /* DMA Source Address Register 2 */
+#define	DCRN_DMASA3	0x0DB    /* DMA Source Address Register 3 */
+#define	DCRN_DMASR	0x0E0    /* DMA Status Register */
+#define	DCRN_EXIER	0x042    /* External Interrupt Enable Register */
+#define	  EXIER_CIE	0x80000000	/* Critical Interrupt Enable */
+#define	  EXIER_SRIE	0x08000000	/* Serial Port Rx Int. Enable */
+#define	  EXIER_STIE	0x04000000	/* Serial Port Tx Int. Enable */
+#define	  EXIER_JRIE	0x02000000	/* JTAG Serial Port Rx Int. Enable */
+#define	  EXIER_JTIE	0x01000000	/* JTAG Serial Port Tx Int. Enable */
+#define	  EXIER_D0IE	0x00800000	/* DMA Channel 0 Interrupt Enable */
+#define	  EXIER_D1IE	0x00400000	/* DMA Channel 1 Interrupt Enable */
+#define	  EXIER_D2IE	0x00200000	/* DMA Channel 2 Interrupt Enable */
+#define	  EXIER_D3IE	0x00100000	/* DMA Channel 3 Interrupt Enable */
+#define	  EXIER_E0IE	0x00000010	/* External Interrupt 0 Enable */
+#define	  EXIER_E1IE	0x00000008	/* External Interrupt 1 Enable */
+#define	  EXIER_E2IE	0x00000004	/* External Interrupt 2 Enable */
+#define	  EXIER_E3IE	0x00000002	/* External Interrupt 3 Enable */
+#define	  EXIER_E4IE	0x00000001	/* External Interrupt 4 Enable */
+#define	DCRN_EXISR	0x040    /* External Interrupt Status Register */
+#define	DCRN_IOCR	0x0A0    /* Input/Output Configuration Register */
+#define	  IOCR_E0TE	0x80000000
+#define	  IOCR_E0LP	0x40000000
+#define	  IOCR_E1TE	0x20000000
+#define	  IOCR_E1LP	0x10000000
+#define	  IOCR_E2TE	0x08000000
+#define	  IOCR_E2LP	0x04000000
+#define	  IOCR_E3TE	0x02000000
+#define	  IOCR_E3LP	0x01000000
+#define	  IOCR_E4TE	0x00800000
+#define	  IOCR_E4LP	0x00400000
+#define	  IOCR_EDT     	0x00080000
+#define	  IOCR_SOR     	0x00040000
+#define	  IOCR_EDO	0x00008000
+#define	  IOCR_2XC	0x00004000
+#define	  IOCR_ATC	0x00002000
+#define	  IOCR_SPD	0x00001000
+#define	  IOCR_BEM	0x00000800
+#define	  IOCR_PTD	0x00000400
+#define	  IOCR_ARE	0x00000080
+#define	  IOCR_DRC	0x00000020
+#define	  IOCR_RDM(x)	(((x) & 0x3) << 3)
+#define	  IOCR_TCS	0x00000004
+#define	  IOCR_SCS	0x00000002
+#define	  IOCR_SPC	0x00000001
+
+
+/* Processor Version Register */
+
+/* Processor Version Register (PVR) field extraction */
+
+#define	PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF)	/* Version field */
+#define	PVR_REV(pvr)  (((pvr) >>   0) & 0xFFFF)	/* Revison field */
+
+/*
+ * IBM has further subdivided the standard PowerPC 16-bit version and
+ * revision subfields of the PVR for the PowerPC 403s into the following:
+ */
+
+#define	PVR_FAM(pvr)	(((pvr) >> 20) & 0xFFF)	/* Family field */
+#define	PVR_MEM(pvr)	(((pvr) >> 16) & 0xF)	/* Member field */
+#define	PVR_CORE(pvr)	(((pvr) >> 12) & 0xF)	/* Core field */
+#define	PVR_CFG(pvr)	(((pvr) >>  8) & 0xF)	/* Configuration field */
+#define	PVR_MAJ(pvr)	(((pvr) >>  4) & 0xF)	/* Major revision field */
+#define	PVR_MIN(pvr)	(((pvr) >>  0) & 0xF)	/* Minor revision field */
+
+/* Processor Version Numbers */
+
+#define	PVR_403GA	0x00200000
+#define	PVR_403GB	0x00200100
+#define	PVR_403GC	0x00200200
+#define	PVR_403GCX	0x00201400
+#define	PVR_405GP	0x40110000
+#define	PVR_601		0x00010000
+#define	PVR_602		0x00050000
+#define	PVR_603		0x00030000
+#define	PVR_603e	0x00060000
+#define	PVR_603ev	0x00070000
+#define	PVR_603r	0x00071000
+#define	PVR_604		0x00040000
+#define	PVR_604e	0x00090000
+#define	PVR_604r	0x000A0000
+#define	PVR_620		0x00140000
+#define	PVR_740		0x00080000
+#define	PVR_750		PVR_740
+#define	PVR_740P	0x10080000
+#define	PVR_750P	PVR_740P
+/*
+ * For the 8xx processors, all of them report the same PVR family for
+ * the PowerPC core. The various versions of these processors must be
+ * differentiated by the version number in the Communication Processor
+ * Module (CPM).
+ */
+#define	PVR_821		0x00500000
+#define	PVR_823		PVR_821
+#define	PVR_850		PVR_821
+#define	PVR_860		PVR_821
+#define	PVR_7400       	0x000C0000
+#define	PVR_8240	0x00810100
+#define	PVR_8260	PVR_8240
+
+
+#define _MACH_prep	0x00000001
+#define _MACH_Pmac	0x00000002	/* pmac or pmac clone (non-chrp) */
+#define _MACH_chrp	0x00000004	/* chrp machine */
+#define _MACH_mbx	0x00000008	/* Motorola MBX board */
+#define _MACH_apus	0x00000010	/* amiga with phase5 powerup */
+#define _MACH_fads	0x00000020	/* Motorola FADS board */
+#define _MACH_rpxlite	0x00000040	/* RPCG RPX-Lite 8xx board */
+#define _MACH_bseip	0x00000080	/* Bright Star Engineering ip-Engine */
+#define _MACH_yk	0x00000100	/* Motorola Yellowknife */
+#define _MACH_gemini	0x00000200	/* Synergy Microsystems gemini board */
+#define _MACH_classic	0x00000400	/* RPCG RPX-Classic 8xx board */
+#define _MACH_oak	0x00000800	/* IBM "Oak" 403 eval. board */
+#define _MACH_walnut	0x00001000	/* IBM "Walnut" 405GP eval. board */
+
 
 /* see residual.h for these */
 #define _PREP_Motorola 0x01  /* motorola prep */
@@ -133,69 +518,27 @@
 	.globl n;\
 n:
 
-#define	TBRU	269	/* Time base Upper/Lower (Reading) */
-#define	TBRL	268
-#define TBWU	284	/* Time base Upper/Lower (Writing) */
-#define TBWL	285
-#define	XER	1
-#define LR	8
-#define CTR	9
-#define HID0	1008	/* Hardware Implementation */
-#define PVR	287	/* Processor Version */
-#define IBAT0U	528	/* Instruction BAT #0 Upper/Lower */
-#define IBAT0L	529
-#define IBAT1U	530	/* Instruction BAT #1 Upper/Lower */
-#define IBAT1L	531
-#define IBAT2U	532	/* Instruction BAT #2 Upper/Lower */
-#define IBAT2L	533
-#define IBAT3U	534	/* Instruction BAT #3 Upper/Lower */
-#define IBAT3L	535
-#define DBAT0U	536	/* Data BAT #0 Upper/Lower */
-#define DBAT0L	537
-#define DBAT1U	538	/* Data BAT #1 Upper/Lower */
-#define DBAT1L	539
-#define DBAT2U	540	/* Data BAT #2 Upper/Lower */
-#define DBAT2L	541
-#define DBAT3U	542	/* Data BAT #3 Upper/Lower */
-#define DBAT3L	543
-#define DMISS	976	/* TLB Lookup/Refresh registers */
-#define DCMP	977
-#define HASH1	978
-#define HASH2	979
-#define IMISS	980
-#define ICMP	981
-#define RPA	982
-#define SDR1	25	/* MMU hash base register */
-#define DAR	19	/* Data Address Register */
-#define SPR0	272	/* Supervisor Private Registers */
-#define SPRG0   272
-#define SPR1	273
-#define SPRG1   273
-#define SPR2	274
-#define SPRG2   274
-#define SPR3	275
-#define SPRG3   275
-#define DSISR	18
-#define SRR0	26	/* Saved Registers (exception) */
-#define SRR1	27
-#define IABR	1010	/* Instruction Address Breakpoint */
-#define DEC	22	/* Decrementer */
-#define EAR	282	/* External Address Register */
-#define L2CR	1017    /* PPC 750 L2 control register */
-#define IMMR	638	/* PPC 860/821 Internal Memory Map Register */
-
-#define THRM1	1020
-#define THRM2	1021
-#define THRM3	1022
-#define THRM1_TIN 0x1
-#define THRM1_TIV 0x2
-#define THRM1_THRES (0x7f<<2)
-#define THRM1_TID (1<<29)
-#define THRM1_TIE (1<<30)
-#define THRM1_V   (1<<31)
-#define THRM3_E   (1<<31)
+/* Macros for setting and retrieving special purpose registers */
+
+#define stringify(s)	tostring(s)
+#define tostring(s)	#s
+
+#define mfdcr(rn)	({unsigned int rval; \
+			asm volatile("mfdcr %0," stringify(rn) \
+				     : "=r" (rval)); rval;})
+#define mtdcr(rn, v)	asm volatile("mtdcr " stringify(rn) ",%0" : : "r" (v))
+
+#define mfmsr()		({unsigned int rval; \
+			asm volatile("mfmsr %0" : "=r" (rval)); rval;})
+#define mtmsr(v)	asm volatile("mtmsr %0" : : "r" (v))
+
+#define mfspr(rn)	({unsigned int rval; \
+			asm volatile("mfspr %0," stringify(rn) \
+				     : "=r" (rval)); rval;})
+#define mtspr(rn, v)	asm volatile("mtspr " stringify(rn) ",%0" : : "r" (v))
 
 /* Segment Registers */
+
 #define SR0	0
 #define SR1	1
 #define SR2	2
@@ -352,6 +695,12 @@
 #define have_of 1
 #elif defined(CONFIG_8xx)
 #define _machine _MACH_8xx
+#define have_of 0
+#elif defined(CONFIG_OAK)
+#define _machine _MACH_oak
+#define have_of	0
+#elif defined(CONFIG_WALNUT)
+#define _machine _MACH_walnut
 #define have_of 0
 #elif defined(CONFIG_APUS)
 #define _machine _MACH_apus
diff -u --recursive --new-file v2.3.38/linux/include/asm-sparc/asmmacro.h linux/include/asm-sparc/asmmacro.h
--- v2.3.38/linux/include/asm-sparc/asmmacro.h	Wed Apr 28 08:47:39 1999
+++ linux/include/asm-sparc/asmmacro.h	Sat Jan  8 21:36:20 2000
@@ -39,9 +39,6 @@
 	or	%tmp, %lo(C_LABEL(cpu_offset)), %tmp; \
 	ld	[%tmp + %reg], %reg;
 
-#define GET_PAGE_OFFSET(reg) \
-	sethi	BTFIXUP_SETHI_INIT(page_offset,0xf0000000), %reg;
-
 /* All trap entry points _must_ begin with this macro or else you
  * lose.  It makes sure the kernel has a proper window so that
  * c-code can be called.
diff -u --recursive --new-file v2.3.38/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v2.3.38/linux/include/asm-sparc/page.h	Sun Jul  4 09:53:12 1999
+++ linux/include/asm-sparc/page.h	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.45 1999/07/03 08:58:05 davem Exp $
+/* $Id: page.h,v 1.46 2000/01/08 16:38:22 anton Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -28,32 +28,14 @@
 #ifndef __ASSEMBLY__
 
 #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
+
 #define PAGE_BUG(page) do { \
-				BUG(); } while (0)
+	BUG(); \
+} while (0)
 
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
 
-extern unsigned long page_offset;
-
-BTFIXUPDEF_SETHI_INIT(page_offset,0xf0000000)
-
-#ifdef MODULE
-#define 	PAGE_OFFSET  (page_offset)
-#else
-#define		PAGE_OFFSET  BTFIXUP_SETHI(page_offset)
-#endif
-
-/* translate between physical and virtual addresses */
-BTFIXUPDEF_CALL_CONST(unsigned long, mmu_v2p, unsigned long)
-BTFIXUPDEF_CALL_CONST(unsigned long, mmu_p2v, unsigned long)
-
-#define mmu_v2p(vaddr) BTFIXUP_CALL(mmu_v2p)(vaddr)
-#define mmu_p2v(paddr) BTFIXUP_CALL(mmu_p2v)(paddr)
-
-#define __pa(x)    (mmu_v2p((unsigned long)(x)))
-#define __va(x)    ((void *)(mmu_p2v((unsigned long)(x))))
-
 /* The following structure is used to hold the physical
  * memory configuration of the machine.  This is filled in
  * probe_memory() and is later used by mem_init() to set up
@@ -273,19 +255,19 @@
 
 #define TASK_UNMAPPED_BASE	BTFIXUP_SETHI(sparc_unmapped_base)
 
-/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-
-/* Now, to allow for very large physical memory configurations we
- * place the page pool both above the kernel and below the kernel.
- */
-#define MAP_NR(addr) ((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT)
-
 #else /* !(__ASSEMBLY__) */
 
 #define __pgprot(x)	(x)
 
 #endif /* !(__ASSEMBLY__) */
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+#define PAGE_OFFSET	0xf0000000
+#define __pa(x)                 ((unsigned long)(x) - PAGE_OFFSET)
+#define __va(x)                 ((void *)((unsigned long) (x) + PAGE_OFFSET))
+#define MAP_NR(addr)            (__pa(addr) >> PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.38/linux/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h
--- v2.3.38/linux/include/asm-sparc/uaccess.h	Wed Dec 29 13:13:21 1999
+++ linux/include/asm-sparc/uaccess.h	Sat Jan  8 21:36:20 2000
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.20 1999/11/23 08:56:45 davem Exp $
+/* $Id: uaccess.h,v 1.21 2000/01/08 16:38:23 anton Exp $
  * uaccess.h: User space memore access functions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -34,10 +34,10 @@
 
 #define segment_eq(a,b)	((a).seg == (b).seg)
 
-/* We have there a nice not-mapped page at page_offset - PAGE_SIZE, so that this test
+/* We have there a nice not-mapped page at PAGE_OFFSET - PAGE_SIZE, so that this test
  * can be fairly lightweight.
  * No one can read/write anything from userland in the kernel space by setting
- * large size and address near to page_offset - a fault will break his intentions.
+ * large size and address near to PAGE_OFFSET - a fault will break his intentions.
  */
 #define __user_ok(addr,size) ((addr) < STACK_TOP)
 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
diff -u --recursive --new-file v2.3.38/linux/include/linux/cyclomx.h linux/include/linux/cyclomx.h
--- v2.3.38/linux/include/linux/cyclomx.h	Fri Sep 10 23:57:37 1999
+++ linux/include/linux/cyclomx.h	Sat Jan  8 21:36:20 2000
@@ -1,10 +1,10 @@
 /*
-* cyclomx.h	CYCLOM X Multiprotocol WAN Link Driver.
+* cyclomx.h	Cyclom 2X WAN Link Driver.
 *		User-level API definitions.
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
 *
 * Based on wanpipe.h by Gene Kozin <genek@compuserve.com>
 *
@@ -15,8 +15,8 @@
 * ============================================================================
 * 1999/05/19	acme		wait_queue_head_t wait_stats(support for 2.3.*)
 * 1999/01/03	acme		judicious use of data types
-* Dec 27, 1998	Arnaldo		cleanup: PACKED not needed
-* Aug 08, 1998	Arnaldo		Version 0.0.1
+* 1998/12/27	acme		cleanup: PACKED not needed
+* 1998/08/08	acme		Version 0.0.1
 */
 #ifndef	_CYCLOMX_H
 #define	_CYCLOMX_H
@@ -28,8 +28,8 @@
 #ifdef	__KERNEL__
 /* Kernel Interface */
 
-#include <linux/cycx_drv.h>	/* CYCLOM X support module API definitions */
-#include <linux/cycx_cfm.h>	/* CYCLOM X firmware module definitions */
+#include <linux/cycx_drv.h>	/* Cyclom 2X support module API definitions */
+#include <linux/cycx_cfm.h>	/* Cyclom 2X firmware module definitions */
 #ifdef CONFIG_CYCLOMX_X25
 #include <linux/cycx_x25.h>
 #endif
diff -u --recursive --new-file v2.3.38/linux/include/linux/cycx_cfm.h linux/include/linux/cycx_cfm.h
--- v2.3.38/linux/include/linux/cycx_cfm.h	Wed Jun  2 14:40:22 1999
+++ linux/include/linux/cycx_cfm.h	Sat Jan  8 21:36:20 2000
@@ -1,9 +1,10 @@
 /*
-* cycx_cfm.h	CYCLOM X Multiprotocol WAN Link Driver.
-*		Definitions for the CYCLOM X Firmware Module (CFM).
+* cycx_cfm.h	Cyclom 2X WAN Link Driver.
+*		Definitions for the Cyclom 2X Firmware Module (CFM).
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
 *
 * Based on sdlasfm.h by Gene Kozin <74604.152@compuserve.com>
 *
@@ -12,7 +13,7 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
-* Aug 08, 1998	Arnaldo		Initial version.
+* 1998/08/08	acme		Initial version.
 */
 #ifndef	_CYCX_CFM_H
 #define	_CYCX_CFM_H
@@ -31,25 +32,25 @@
 /* Firmware Commands */
 #define GEN_POWER_ON	0x1280
 
-#define GEN_SET_SEG	0x1401	/* boot segment setting.        */
-#define GEN_BOOT_DAT	0x1402	/* boot data.                   */
-#define GEN_START	0x1403	/* board start.                 */
-#define GEN_DEFPAR	0x1404	/* buffer length for boot.      */
+#define GEN_SET_SEG	0x1401	/* boot segment setting. */
+#define GEN_BOOT_DAT	0x1402	/* boot data. */
+#define GEN_START	0x1403	/* board start. */
+#define GEN_DEFPAR	0x1404	/* buffer length for boot. */
 
-/* Adapter types */
+/* Adapter Types */
 #define CYCX_2X		2
+/* for now only the 2X is supported, no plans to support 8X or 16X */
 #define CYCX_8X		8
 #define CYCX_16X	16
 
 #define	CFID_X25_2X	5200
 
-
 /* Data Types */
 
 typedef struct	cfm_info		/* firmware module information */
 {
 	unsigned short	codeid;		/* firmware ID */
-	unsigned short	version;	/* firmaware version number */
+	unsigned short	version;	/* firmware version number */
 	unsigned short	adapter[CFM_MAX_CYCX]; /* compatible adapter types */
 	unsigned long	memsize;	/* minimum memory size */
 	unsigned short	reserved[2];	/* reserved */
@@ -61,7 +62,7 @@
 	unsigned long	datasize;	/* configuration data size */
 } cfm_info_t;
 
-typedef struct cfm			/* CYCX firmware file structire */
+typedef struct cfm			/* CYCX firmware file structure */
 {
 	char		signature[80];	/* CFM file signature */
 	unsigned short	version;	/* file format version */
diff -u --recursive --new-file v2.3.38/linux/include/linux/cycx_drv.h linux/include/linux/cycx_drv.h
--- v2.3.38/linux/include/linux/cycx_drv.h	Thu Nov 18 20:25:38 1999
+++ linux/include/linux/cycx_drv.h	Sat Jan  8 21:36:20 2000
@@ -2,7 +2,8 @@
 * cycx_drv.h	CYCX Support Module.  Kernel API Definitions.
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+*
+* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
 *
 * Based on sdladrv.h by Gene Kozin <genek@compuserve.com>
 *
diff -u --recursive --new-file v2.3.38/linux/include/linux/cycx_x25.h linux/include/linux/cycx_x25.h
--- v2.3.38/linux/include/linux/cycx_x25.h	Wed Jun  2 14:40:22 1999
+++ linux/include/linux/cycx_x25.h	Sat Jan  8 21:36:20 2000
@@ -3,7 +3,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998, 1999 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
 *
 * Based on sdla_x25.h by Gene Kozin <74604.152@compuserve.com>
 *
@@ -13,9 +13,8 @@
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
 * 1999/01/03	acme		judicious use of data types
-*
 * 1999/01/02	acme		#define X25_ACK_N3	0x4411
-* Dec 28, 1998	Arnaldo		cleanup: lot'o'things removed
+* 1998/12/28	acme		cleanup: lot'o'things removed
 *					 commands listed,
 *					 TX25Cmd & TX25Config structs
 *					 typedef'ed
@@ -31,7 +30,7 @@
 #define	X25_MBOX_OFFS	0x300	/* general mailbox block */
 #define	X25_RXMBOX_OFFS	0x340	/* receive mailbox */
 
-/* DATA STRUCTURES */
+/* Data Structures */
 /* X.25 Command Block. */
 typedef struct X25Cmd
 {
diff -u --recursive --new-file v2.3.38/linux/include/linux/elfcore.h linux/include/linux/elfcore.h
--- v2.3.38/linux/include/linux/elfcore.h	Wed Aug 18 16:45:32 1999
+++ linux/include/linux/elfcore.h	Mon Jan 10 18:29:33 2000
@@ -71,8 +71,8 @@
 	char	pr_zomb;	/* zombie */
 	char	pr_nice;	/* nice val */
 	unsigned long pr_flag;	/* flags */
-	uid_t	pr_uid;
-	gid_t	pr_gid;
+	__kernel_uid_t	pr_uid;
+	__kernel_gid_t	pr_gid;
 	pid_t	pr_pid, pr_ppid, pr_pgrp, pr_sid;
 	/* Lots missing */
 	char	pr_fname[16];	/* filename of executable */
diff -u --recursive --new-file v2.3.38/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.3.38/linux/include/linux/ext2_fs.h	Tue Jan  4 13:57:21 2000
+++ linux/include/linux/ext2_fs.h	Mon Jan 10 18:29:05 2000
@@ -216,13 +216,13 @@
  */
 struct ext2_inode {
 	__u16	i_mode;		/* File mode */
-	__u16	i_uid;		/* Owner Uid */
+	__u16	i_uid;		/* Low 16 bits of Owner Uid */
 	__u32	i_size;		/* Size in bytes */
 	__u32	i_atime;	/* Access time */
 	__u32	i_ctime;	/* Creation time */
 	__u32	i_mtime;	/* Modification time */
 	__u32	i_dtime;	/* Deletion Time */
-	__u16	i_gid;		/* Group Id */
+	__u16	i_gid;		/* Low 16 bits of Group Id */
 	__u16	i_links_count;	/* Links count */
 	__u32	i_blocks;	/* Blocks count */
 	__u32	i_flags;	/* File flags */
@@ -247,7 +247,9 @@
 			__u8	l_i_frag;	/* Fragment number */
 			__u8	l_i_fsize;	/* Fragment size */
 			__u16	i_pad1;
-			__u32	l_i_reserved2[2];
+			__u16	l_i_uid_high;	/* these 2 fields    */
+			__u16	l_i_gid_high;	/* were reserved2[0] */
+			__u32	l_i_reserved2;
 		} linux2;
 		struct {
 			__u8	h_i_frag;	/* Fragment number */
@@ -272,6 +274,10 @@
 #define i_reserved1	osd1.linux1.l_i_reserved1
 #define i_frag		osd2.linux2.l_i_frag
 #define i_fsize		osd2.linux2.l_i_fsize
+#define i_uid_low	i_uid
+#define i_gid_low	i_gid
+#define i_uid_high	osd2.linux2.l_i_uid_high
+#define i_gid_high	osd2.linux2.l_i_gid_high
 #define i_reserved2	osd2.linux2.l_i_reserved2
 #endif
 
@@ -310,6 +316,7 @@
 #define EXT2_MOUNT_ERRORS_RO		0x0020	/* Remount fs ro on errors */
 #define EXT2_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */
 #define EXT2_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
+#define EXT2_MOUNT_NO_UID32		0x0200  /* Disable 32-bit UIDs */
 
 #define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt
 #define set_opt(o, opt)			o |= EXT2_MOUNT_##opt
diff -u --recursive --new-file v2.3.38/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h
--- v2.3.38/linux/include/linux/ext2_fs_sb.h	Mon Jun 28 11:25:56 1999
+++ linux/include/linux/ext2_fs_sb.h	Mon Jan 10 18:29:05 2000
@@ -50,8 +50,8 @@
 	unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
 	struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
 	unsigned long  s_mount_opt;
-	unsigned short s_resuid;
-	unsigned short s_resgid;
+	uid_t s_resuid;
+	gid_t s_resgid;
 	unsigned short s_mount_state;
 	unsigned short s_pad;
 	int s_addr_per_block_bits;
diff -u --recursive --new-file v2.3.38/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.38/linux/include/linux/fs.h	Fri Jan  7 19:13:23 2000
+++ linux/include/linux/fs.h	Mon Jan 10 18:29:19 2000
@@ -277,6 +277,7 @@
 #include <linux/udf_fs_i.h>
 #include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
+#include <linux/usbdev_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -414,6 +415,7 @@
 		struct ncp_inode_info		ncpfs_i;
 		struct proc_inode_info		proc_i;
 		struct socket			socket_i;
+		struct usbdev_inode_info        usbdev_i;
 		void				*generic_ip;
 	} u;
 };
@@ -545,6 +547,7 @@
 #include <linux/bfs_fs_sb.h>
 #include <linux/udf_fs_sb.h>
 #include <linux/ncp_fs_sb.h>
+#include <linux/usbdev_fs_sb.h>
 
 extern struct list_head super_blocks;
 
@@ -592,6 +595,7 @@
 		struct bfs_sb_info	bfs_sb;
 		struct udf_sb_info	udf_sb;
 		struct ncp_sb_info	ncpfs_sb;
+		struct usbdev_sb_info   usbdevfs_sb;
 		void			*generic_sbp;
 	} u;
 	/*
@@ -769,6 +773,7 @@
 extern struct block_device *bdget(dev_t);
 extern void bdput(struct block_device *);
 extern int blkdev_open(struct inode *, struct file *);
+extern int blkdev_close(struct inode *, struct file *);
 extern struct file_operations def_blk_fops;
 extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
 extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
@@ -810,7 +815,8 @@
 #define BUF_CLEAN	0
 #define BUF_LOCKED	1	/* Buffers scheduled for write */
 #define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write */
-#define NR_LIST		3
+#define BUF_PROTECTED	3	/* Ramdisk persistent storage */
+#define NR_LIST		4
 
 /*
  * This is called by bh->b_end_io() handlers when I/O has completed.
@@ -836,6 +842,19 @@
 		__mark_buffer_clean(bh);
 }
 
+#define atomic_set_buffer_protected(bh) test_and_set_bit(BH_Protected, &(bh)->b_state)
+
+extern inline void __mark_buffer_protected(struct buffer_head *bh)
+{
+	refile_buffer(bh);
+}
+
+extern inline void mark_buffer_protected(struct buffer_head * bh)
+{
+	if (!atomic_set_buffer_protected(bh))
+		__mark_buffer_protected(bh);
+}
+
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh, int flag));
 
 #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
@@ -1006,12 +1025,12 @@
 
 extern ssize_t char_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t block_read(struct file *, char *, size_t, loff_t *);
+extern int block_fsync(struct file *, struct dentry *);
 extern int read_ahead[];
 
 extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
 extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
 
-extern int block_fsync(struct file *, struct dentry *);
 extern int file_fsync(struct file *, struct dentry *);
 extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx);
 
diff -u --recursive --new-file v2.3.38/linux/include/linux/highuid.h linux/include/linux/highuid.h
--- v2.3.38/linux/include/linux/highuid.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/highuid.h	Mon Jan 10 18:29:08 2000
@@ -0,0 +1,104 @@
+#ifndef _LINUX_HIGHUID_H
+#define _LINUX_HIGHUID_H
+
+#include <linux/types.h>
+
+/*
+ * general notes:
+ *
+ * UID16_COMPAT_NEEDED is defined in include/asm-{arch}/posix_types.h
+ * if the given architecture needs to support backwards compatibility
+ * for old system calls.
+ *
+ * old_uid_t and old_gid_t are only used if UID16_COMPAT_NEEDED
+ * is defined.
+ *
+ * uid16_t and gid16_t are used on all architectures. (when dealing
+ * with structures hard coded to 16 bits, such as in filesystems)
+ */
+
+
+#ifdef UID16_COMPAT_NEEDED
+
+/*
+ * This is the "overflow" UID and GID. They are used to signify uid/gid
+ * overflow to old programs when they request uid/gid information but are
+ * using the old 16 bit interfaces.
+ * When you run a libc5 program, it will think that all highuid files or
+ * processes are owned by this uid/gid.
+ * The idea is that it's better to do so than possibly return 0 in lieu of
+ * 65536, etc.
+ */
+
+extern int overflowuid;
+extern int overflowgid;
+
+#define DEFAULT_OVERFLOWUID	65534
+#define DEFAULT_OVERFLOWGID	65534
+
+
+/* prevent uid mod 65536 effect by returning a default value for high UIDs */
+#define high2lowuid(uid) ((uid) > 65535) ? (old_uid_t)overflowuid : (old_uid_t)(uid)
+#define high2lowgid(gid) ((gid) > 65535) ? (old_gid_t)overflowgid : (old_gid_t)(gid)
+/*
+ * -1 is different in 16 bits than it is in 32 bits
+ * these macros are used by chown(), setreuid(), ...,
+ */
+#define low2highuid(uid) ((uid) == (old_uid_t)-1) ? (uid_t)-1 : (uid_t)(uid)
+#define low2highgid(gid) ((gid) == (old_gid_t)-1) ? (gid_t)-1 : (gid_t)(gid)
+
+/* Avoid extra ifdefs with these macros */
+
+#define SET_UID16(var, uid)	var = high2lowuid(uid)
+#define SET_GID16(var, gid)	var = high2lowgid(gid)
+#define NEW_TO_OLD_UID(uid)	high2lowuid(uid)
+#define NEW_TO_OLD_GID(gid)	high2lowgid(gid)
+
+#define SET_OLDSTAT_UID(stat, uid)	(stat).st_uid = high2lowuid(uid)
+#define SET_OLDSTAT_GID(stat, gid)	(stat).st_gid = high2lowgid(gid)
+#define SET_STAT_UID(stat, uid)		(stat).st_uid = high2lowuid(uid)
+#define SET_STAT_GID(stat, gid)		(stat).st_gid = high2lowgid(gid)
+
+#else
+
+#define SET_UID16(var, uid)	do { ; } while (0)
+#define SET_GID16(var, gid)	do { ; } while (0)
+#define NEW_TO_OLD_UID(uid)	uid
+#define NEW_TO_OLD_GID(gid)	gid
+
+#define SET_OLDSTAT_UID(stat, uid)	(stat).st_uid = uid
+#define SET_OLDSTAT_GID(stat, gid)	(stat).st_gid = gid
+#define SET_STAT_UID(stat, uid)		(stat).st_uid = uid
+#define SET_STAT_GID(stat, gid)		(stat).st_gid = gid
+
+#define high2lowuid(x)		(x)
+
+#endif /* UID16_COMPAT_NEEDED */
+
+
+/*
+ * Everything below this line is needed on all architectures, to deal with
+ * filesystems that only store 16 bits of the UID/GID, etc.
+ */
+
+/*
+ * This is the UID and GID that will get written to disk if a filesystem
+ * only supports 16-bit UIDs and the kernel has a high UID/GID to write
+ */
+extern int fs_overflowuid;
+extern int fs_overflowgid;
+
+#define DEFAULT_FS_OVERFLOWUID	65534
+#define DEFAULT_FS_OVERFLOWGID	65534
+
+/*
+ * Since these macros are used in architectures that only need limited
+ * 16-bit UID back compatibility, we won't use old_uid_t and old_gid_t
+ */
+#define fs_high2lowuid(uid) (uid > 65535) ? (uid16_t)fs_overflowuid : (uid16_t)uid
+#define fs_high2lowgid(gid) (gid > 65535) ? (gid16_t)fs_overflowgid : (gid16_t)gid
+
+#define low_16_bits(x)	x & 0xFFFF
+#define high_16_bits(x)	(x & 0xFFFF0000) >> 16
+
+#endif /* _LINUX_HIGHUID_H */
diff -u --recursive --new-file v2.3.38/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.3.38/linux/include/linux/i2o.h	Thu Nov 11 20:11:53 1999
+++ linux/include/linux/i2o.h	Mon Jan 10 14:05:33 2000
@@ -26,12 +26,8 @@
 #define I2OSWDEL		_IOWR(I2O_MAGIC_NUMBER,7,struct i2o_sw_xfer)
 #define I2OVALIDATE		_IOR(I2O_MAGIC_NUMBER,8,u32)
 #define I2OHTML			_IOWR(I2O_MAGIC_NUMBER,9,struct i2o_html)
-
-/* On hold until we figure this out
-#define I2OEVTREG		_IO(I2O_MAGIC_NUMBER,10)
-#define I2OEVTCLR		_IO(I2O_MAGIC_NUMBER,11)
-#define I2OEVTGET		_IO(I2O_MAGIC_NUMBER,12)
- */
+#define I2OEVTREG		_IOW(I2O_MAGIC_NUMBER,10,struct i2o_evt_id)
+#define I2OEVTGET		_IOR(I2O_MAGIC_NUMBER,11,struct i2o_evt_info)
 
 struct i2o_cmd_hrtlct
 {
@@ -73,6 +69,33 @@
 	unsigned int qlen;	/* Length in bytes of query string buffer */
 };
 
+#define I2O_EVT_Q_LEN 32
+
+struct i2o_evt_id
+{
+	unsigned int iop;
+	unsigned int tid;
+	unsigned int evt_mask;
+};
+
+//
+// Event data size = frame size - message header + evt indicator
+#define I2O_EVT_DATA_SIZE 88
+
+struct i2o_evt_info
+{
+	struct i2o_evt_id id;
+	unsigned char evt_data[I2O_EVT_DATA_SIZE];
+ 	unsigned int data_size;
+};
+
+struct i2o_evt_get
+{
+	struct i2o_evt_info info;
+	int pending;
+	int lost;
+};
+
 
 /**************************************************************************
  * HRT related constants and structures
@@ -263,8 +286,12 @@
 
 struct i2o_message
 {
-	u32	version_size;
-	u32	function_addr;
+	u8	version_offset;
+	u8	flags;
+	u16	size;
+	u32	target_tid:12;
+	u32	init_tid:12;
+	u32	function:8;	
 	u32	initiator_context;
 	/* List follows */
 };
@@ -471,14 +498,8 @@
 	I2O_REPLY_WRITE32(c,m);
 }
 
-
-struct i2o_controller *i2o_controller_chain;
-
-extern int i2o_quiesce_controller(struct i2o_controller *);
-extern int i2o_clear_controller(struct i2o_controller *);
 extern int i2o_install_controller(struct i2o_controller *);
 extern int i2o_delete_controller(struct i2o_controller *);
-extern int i2o_activate_controller(struct i2o_controller *);
 extern void i2o_unlock_controller(struct i2o_controller *);
 extern struct i2o_controller *i2o_find_controller(int);
 extern int i2o_status_get(struct i2o_controller *);
@@ -487,8 +508,6 @@
 extern int i2o_install_handler(struct i2o_handler *);
 extern int i2o_remove_handler(struct i2o_handler *);
 
-extern int i2o_install_device(struct i2o_controller *, struct i2o_device *);
-extern int i2o_delete_device(struct i2o_device *);
 extern int i2o_claim_device(struct i2o_device *, struct i2o_handler *, u32);
 extern int i2o_release_device(struct i2o_device *, struct i2o_handler *, u32);
 
@@ -505,14 +524,13 @@
 extern int i2o_clear_table(struct i2o_controller *, int, int); 
 extern int i2o_row_add_table(struct i2o_controller *, int, int, int, void *,
 			     int);
-extern int i2o_row_delete_table(struct i2o_controller *, int, int, int, void *,
-				int);
 
 extern int i2o_event_register(struct i2o_controller *, int, int, u32); 
 extern int i2o_event_ack(struct i2o_controller *, int, int, u32, void *, int);
 
 extern void i2o_run_queue(struct i2o_controller *);
 extern void i2o_report_status(const char *, const char *, u32 *);
+extern void i2o_dump_message(u32 *);
 
 extern const char *i2o_get_class_name(int);
 
diff -u --recursive --new-file v2.3.38/linux/include/linux/ipc.h linux/include/linux/ipc.h
--- v2.3.38/linux/include/linux/ipc.h	Tue Dec  7 09:32:51 1999
+++ linux/include/linux/ipc.h	Mon Jan 10 18:29:05 2000
@@ -5,6 +5,7 @@
 
 #define IPC_PRIVATE ((__kernel_key_t) 0)  
 
+/* Obsolete, used only for backwards compatibility and libc5 compiles */
 struct ipc_perm
 {
 	__kernel_key_t	key;
@@ -16,6 +17,9 @@
 	unsigned short	seq;
 };
 
+/* Include the definition of ipc64_perm */
+#include <asm/ipcbuf.h>
+
 /* resource get request flags */
 #define IPC_CREAT  00001000   /* create if key is nonexistent */
 #define IPC_EXCL   00002000   /* fail if key exists */
@@ -36,9 +40,30 @@
 #define IPC_STAT 2     /* get ipc_perm options */
 #define IPC_INFO 3     /* see ipcs */
 
+/*
+ * Version flags for semctl, msgctl, and shmctl commands
+ * These are passed as bitflags or-ed with the actual command
+ */
+#define IPC_OLD 0	/* Old version (no 32-bit UID support on many
+			   architectures) */
+#define IPC_64  0x0100  /* New version (support 32-bit UIDs, bigger
+			   message sizes, etc. */
+
 #ifdef __KERNEL__
 
 #define IPCMNI 32768  /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
+
+/* used by in-kernel data structures */
+struct kern_ipc_perm
+{
+	key_t		key;
+	uid_t		uid;
+	gid_t		gid;
+	uid_t		cuid;
+	gid_t		cgid;
+	mode_t		mode; 
+	unsigned long	seq;
+};
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.38/linux/include/linux/isapnp.h linux/include/linux/isapnp.h
--- v2.3.38/linux/include/linux/isapnp.h	Fri Jan  7 19:13:23 2000
+++ linux/include/linux/isapnp.h	Mon Jan 10 18:30:50 2000
@@ -146,6 +146,8 @@
 void isapnp_deactivate(unsigned char device);
 void isapnp_fixup_device(struct pci_dev *dev);
 void *isapnp_alloc(long size);
+int isapnp_proc_init(void);
+int isapnp_proc_done(void);
 /* manager */
 struct pci_bus *isapnp_find_card(unsigned short vendor,
 				 unsigned short device,
@@ -161,6 +163,14 @@
 /* init/main.c */
 int isapnp_init(void);
 
+extern struct list_head isapnp_cards;
+extern struct list_head isapnp_devices;
+
+#define isapnp_for_each_card(card) \
+	for(card = pci_bus_b(isapnp_cards.next); card != pci_bus_b(&isapnp_cards); card = pci_bus_b(card->node.next))
+#define isapnp_for_each_dev(dev) \
+	for(dev = pci_dev_g(isapnp_devices.next); dev != pci_dev_g(&isapnp_devices); dev = pci_dev_g(dev->global_list.next))
+
 #else /* !CONFIG_ISAPNP */
 
 /* lowlevel configuration */
@@ -173,21 +183,21 @@
 extern inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
 extern inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
 extern inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
-extern void isapnp_wake(unsigned char csn) { ; }
-extern void isapnp_device(unsigned char device) { ; }
-extern void isapnp_activate(unsigned char device) { ; }
-extern void isapnp_deactivate(unsigned char device) { ; }
+extern inline void isapnp_wake(unsigned char csn) { ; }
+extern inline void isapnp_device(unsigned char device) { ; }
+extern inline void isapnp_activate(unsigned char device) { ; }
+extern inline void isapnp_deactivate(unsigned char device) { ; }
 /* manager */
-extern struct pci_bus *isapnp_find_card(unsigned short vendor,
-				        unsigned short device,
-				        struct pci_bus *from) { return NULL; }
-extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
-				       unsigned short vendor,
-				       unsigned short function,
+extern inline struct pci_bus *isapnp_find_card(unsigned short vendor,
+					       unsigned short device,
+					       struct pci_bus *from) { return NULL; }
+extern inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+					      unsigned short vendor,
+					      unsigned short function,
 				       struct pci_dev *from) { return NULL; }
-extern void isapnp_resource_change(struct resource *resource,
-				   unsigned long start,
-				   unsigned long size) { ; }
+extern inline void isapnp_resource_change(struct resource *resource,
+					  unsigned long start,
+					  unsigned long size) { ; }
 
 #endif /* CONFIG_ISAPNP */
 
diff -u --recursive --new-file v2.3.38/linux/include/linux/msg.h linux/include/linux/msg.h
--- v2.3.38/linux/include/linux/msg.h	Tue Dec  7 09:32:51 1999
+++ linux/include/linux/msg.h	Mon Jan 10 18:30:41 2000
@@ -11,6 +11,7 @@
 #define MSG_NOERROR     010000  /* no error if message is too big */
 #define MSG_EXCEPT      020000  /* recv any msg except of specified type.*/
 
+/* Obsolete, used only for backwards compatibility and libc5 compiles */
 struct msqid_ds {
 	struct ipc_perm msg_perm;
 	struct msg *msg_first;		/* first message on queue,unused  */
@@ -26,6 +27,9 @@
 	__kernel_ipc_pid_t msg_lspid;	/* pid of last msgsnd */
 	__kernel_ipc_pid_t msg_lrpid;	/* last receive pid */
 };
+
+/* Include the definition of msqid64_ds */
+#include <asm/msgbuf.h>
 
 /* message buffer for msgsnd and msgrcv calls */
 struct msgbuf {
diff -u --recursive --new-file v2.3.38/linux/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h
--- v2.3.38/linux/include/linux/ncp_fs.h	Wed Dec  8 14:11:28 1999
+++ linux/include/linux/ncp_fs.h	Mon Jan 10 18:31:28 2000
@@ -124,6 +124,8 @@
 #define NCP_IOC_GETDENTRYTTL		_IOW('n', 12, __u32)
 #define NCP_IOC_SETDENTRYTTL		_IOR('n', 12, __u32)
 
+#define	NCP_IOC_GETMOUNTUID32		_IOW('n', 13, __kernel_uid32_t)
+
 /*
  * The packet size to allocate. One page should be enough.
  */
diff -u --recursive --new-file v2.3.38/linux/include/linux/ntfs_fs_i.h linux/include/linux/ntfs_fs_i.h
--- v2.3.38/linux/include/linux/ntfs_fs_i.h	Mon Jan  4 10:41:35 1999
+++ linux/include/linux/ntfs_fs_i.h	Mon Jan 10 18:15:58 2000
@@ -24,11 +24,11 @@
 #endif
 #ifndef NTFS_UID_T
 #define NTFS_UID_T
-typedef __kernel_uid_t ntfs_uid_t;
+typedef uid_t ntfs_uid_t;
 #endif
 #ifndef NTFS_GID_T
 #define NTFS_GID_T
-typedef __kernel_gid_t ntfs_gid_t;
+typedef gid_t ntfs_gid_t;
 #endif
 #ifndef NTFS_SIZE_T
 #define NTFS_SIZE_T
diff -u --recursive --new-file v2.3.38/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.38/linux/include/linux/pci.h	Fri Jan  7 19:13:23 2000
+++ linux/include/linux/pci.h	Mon Jan 10 18:29:08 2000
@@ -311,9 +311,10 @@
 	unsigned short	subsystem_device;
 	unsigned int	class;		/* 3 bytes: (base,sub,prog-if) */
 	u8		hdr_type;	/* PCI header type (`multi' flag masked out) */
-	u8		rom_base_reg;	/* Which config register controls the ROM */
+	u8		rom_base_reg;	/* which config register controls the ROM */
 
-	unsigned short	regs;
+	struct pci_driver *driver;	/* which driver has allocated this device */
+	void		*driver_data;	/* data private to the driver */
 
 	/* device is compatible with these IDs */
 	unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
@@ -328,12 +329,13 @@
 	struct resource dma_resource[DEVICE_COUNT_DMA];
 	struct resource irq_resource[DEVICE_COUNT_IRQ];
 
-	char		name[48];	/* Device name */
-	char		slot_name[8];	/* Slot name */
-	int active;			/* device is active */
-	int ro;				/* Read/Only */
+	char		name[48];	/* device name */
+	char		slot_name[8];	/* slot name */
+	int		active;		/* ISAPnP: device is active */
+	int		ro;		/* ISAPnP: read only */
+	unsigned short	regs;		/* ISAPnP: supported registers */
 
-	int (*prepare)(struct pci_dev *dev);
+	int (*prepare)(struct pci_dev *dev);	/* ISAPnP hooks */
 	int (*activate)(struct pci_dev *dev);
 	int (*deactivate)(struct pci_dev *dev);
 };
@@ -497,6 +499,23 @@
 void pci_set_bus_ranges(void);
 void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
 		    int (*)(struct pci_dev *, u8, u8));
+
+/* New-style probing supporting hot-pluggable devices */
+
+struct pci_driver {
+	struct list_head node;
+	char *name;
+	int (*probe)(struct pci_dev *dev);	/* New device inserted, check if known */
+	void (*remove)(struct pci_dev *dev);	/* Device removed */
+	void (*suspend)(struct pci_dev *dev);	/* Device suspended */
+	void (*resume)(struct pci_dev *dev);	/* Device woken up */
+};
+
+void pci_register_driver(struct pci_driver *);
+void pci_unregister_driver(struct pci_driver *);
+void pci_insert_device(struct pci_dev *, struct pci_bus *);
+void pci_remove_device(struct pci_dev *);
+struct pci_driver *pci_dev_driver(struct pci_dev *);
 
 /*
  * simple PCI probing for drivers (drivers/pci/helper.c)
diff -u --recursive --new-file v2.3.38/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.3.38/linux/include/linux/pci_ids.h	Wed Dec 29 13:13:21 1999
+++ linux/include/linux/pci_ids.h	Mon Jan 10 12:19:09 2000
@@ -163,6 +163,10 @@
 #define PCI_DEVICE_ID_ATI_215LG		0x4c47
 #define PCI_DEVICE_ID_ATI_264LT		0x4c54
 #define PCI_DEVICE_ID_ATI_264VT		0x5654
+#define PCI_DEVICE_ID_ATI_RAGE128_RE	0x5245
+#define PCI_DEVICE_ID_ATI_RAGE128_RF	0x5246
+#define PCI_DEVICE_ID_ATI_RAGE128_RK	0x524b
+#define PCI_DEVICE_ID_ATI_RAGE128_RL	0x524c
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
diff -u --recursive --new-file v2.3.38/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.38/linux/include/linux/proc_fs.h	Wed Dec 29 13:13:21 1999
+++ linux/include/linux/proc_fs.h	Mon Jan 10 18:30:03 2000
@@ -181,11 +181,11 @@
 	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 proc_dir_entry *proc_symlink(const char *name,
+extern inline struct proc_dir_entry *proc_symlink(const char *name,
 		struct proc_dir_entry *parent,char *dest) {return NULL;}
-extern inline proc_dir_entry *proc_mknod(const char *name,mode_t mode,
+extern inline struct proc_dir_entry *proc_mknod(const char *name,mode_t mode,
 		struct proc_dir_entry *parent,kdev_t rdev) {return NULL;}
-extern struct proc_dir_entry *proc_mkdir(const char *name,
+extern 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,
diff -u --recursive --new-file v2.3.38/linux/include/linux/qnx4_fs.h linux/include/linux/qnx4_fs.h
--- v2.3.38/linux/include/linux/qnx4_fs.h	Wed Dec 29 13:13:21 1999
+++ linux/include/linux/qnx4_fs.h	Mon Jan 10 14:19:46 2000
@@ -2,8 +2,8 @@
  *  Name                         : qnx4_fs.h
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 global filesystem definitions
- *  Version                      : 1.0.1
- *  Last modified                : 1999-12-13
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-06
  *
  *  History                      : 23-03-1998 created
  */
@@ -41,41 +41,41 @@
  * This is the original qnx4 inode layout on disk.
  */
 struct qnx4_inode_entry {
-	char di_fname[QNX4_SHORT_NAME_MAX];
-	qnx4_off_t di_size;
-	qnx4_xtnt_t di_first_xtnt;
-	unsigned long di_xblk;
-	time_t di_ftime;
-	time_t di_mtime;
-	time_t di_atime;
-	time_t di_ctime;
-	qnx4_nxtnt_t di_num_xtnts;
-	mode_t di_mode;
-	qnx4_muid_t di_uid;
-	qnx4_mgid_t di_gid;
-	qnx4_nlink_t di_nlink;
-	char di_zero[4];
-	qnx4_ftype_t di_type;
-	unsigned char di_status;
+	char		di_fname[QNX4_SHORT_NAME_MAX];
+	qnx4_off_t	di_size;
+	qnx4_xtnt_t	di_first_xtnt;
+	__u32		di_xblk;
+	__s32		di_ftime;
+	__s32		di_mtime;
+	__s32		di_atime;
+	__s32		di_ctime;
+	qnx4_nxtnt_t	di_num_xtnts;
+	qnx4_mode_t	di_mode;
+	qnx4_muid_t	di_uid;
+	qnx4_mgid_t	di_gid;
+	qnx4_nlink_t	di_nlink;
+	__u8		di_zero[4];
+	qnx4_ftype_t	di_type;
+	__u8		di_status;
 };
 
 struct qnx4_link_info {
-	char dl_fname[QNX4_NAME_MAX];
-	unsigned long dl_inode_blk;
-	unsigned char dl_inode_ndx;
-	unsigned char dl_spare[10];
-	unsigned char dl_status;
+	char		dl_fname[QNX4_NAME_MAX];
+	__u32		dl_inode_blk;
+	__u8		dl_inode_ndx;
+	__u8		dl_spare[10];
+	__u8		dl_status;
 };
 
 struct qnx4_xblk {
-	unsigned long xblk_next_xblk;
-	unsigned long xblk_prev_xblk;
-	unsigned char xblk_num_xtnts;
-	char xblk_spare[3];
-	long xblk_num_blocks;
-	qnx4_xtnt_t xblk_xtnts[QNX4_MAX_XTNTS_PER_XBLK];
-	char xblk_signature[8];
-	qnx4_xtnt_t xblk_first_xtnt;
+	__u32		xblk_next_xblk;
+	__u32		xblk_prev_xblk;
+	__u8		xblk_num_xtnts;
+	__u8		xblk_spare[3];
+	__s32		xblk_num_blocks;
+	qnx4_xtnt_t	xblk_xtnts[QNX4_MAX_XTNTS_PER_XBLK];
+	char		xblk_signature[8];
+	qnx4_xtnt_t	xblk_first_xtnt;
 };
 
 struct qnx4_super_block {
diff -u --recursive --new-file v2.3.38/linux/include/linux/qnx4_fs_i.h linux/include/linux/qnx4_fs_i.h
--- v2.3.38/linux/include/linux/qnx4_fs_i.h	Wed Dec 29 13:13:21 1999
+++ linux/include/linux/qnx4_fs_i.h	Mon Jan 10 14:19:46 2000
@@ -2,11 +2,11 @@
  *  Name                         : qnx4_fs_i.h
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 inode definitions
- *  Version                      : 1.0
- *  Last modified                : 25-05-1998
- * 
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-06
+ *
  *  History                      : 23-03-1998 created
- * 
+ *
  */
 #ifndef _QNX4_FS_I
 #define _QNX4_FS_I
@@ -14,25 +14,25 @@
 #include <linux/qnxtypes.h>
 
 /*
- * qnx4 fs inode entry 
+ * qnx4 fs inode entry
  */
 struct qnx4_inode_info {
-	char i_reserved[16];	/* 16 */
-	qnx4_off_t i_size;		/*  4 */
-	qnx4_xtnt_t i_first_xtnt;	/*  8 */
-	long i_xblk;		/*  4 */
-	time_t i_ftime;		/*  4 */
-	time_t i_mtime;		/*  4 */
-	time_t i_atime;		/*  4 */
-	time_t i_ctime;		/*  4 */
-	qnx4_nxtnt_t i_num_xtnts;	/*  2 */
-	mode_t i_mode;		/*  2 */
-	qnx4_muid_t i_uid;		/*  2 */
-	qnx4_mgid_t i_gid;		/*  2 */
-	qnx4_nlink_t i_nlink;	/*  2 */
-	char i_zero[4];		/*  4 */
-	qnx4_ftype_t i_type;	/*  1 */
-	unsigned char i_status;	/*  1 */
+	char		i_reserved[16];	/* 16 */
+	qnx4_off_t	i_size;		/*  4 */
+	qnx4_xtnt_t	i_first_xtnt;	/*  8 */
+	__u32		i_xblk;		/*  4 */
+	__s32		i_ftime;	/*  4 */
+	__s32		i_mtime;	/*  4 */
+	__s32		i_atime;	/*  4 */
+	__s32		i_ctime;	/*  4 */
+	qnx4_nxtnt_t	i_num_xtnts;	/*  2 */
+	qnx4_mode_t	i_mode;		/*  2 */
+	qnx4_muid_t	i_uid;		/*  2 */
+	qnx4_mgid_t	i_gid;		/*  2 */
+	qnx4_nlink_t	i_nlink;	/*  2 */
+	__u8		i_zero[4];	/*  4 */
+	qnx4_ftype_t	i_type;		/*  1 */
+	__u8		i_status;	/*  1 */
 };
 
 #endif
diff -u --recursive --new-file v2.3.38/linux/include/linux/qnx4_fs_sb.h linux/include/linux/qnx4_fs_sb.h
--- v2.3.38/linux/include/linux/qnx4_fs_sb.h	Wed Dec 29 13:13:21 1999
+++ linux/include/linux/qnx4_fs_sb.h	Mon Jan 10 14:19:46 2000
@@ -2,8 +2,8 @@
  *  Name                         : qnx4_fs_sb.h
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 superblock definitions
- *  Version                      : 1.0
- *  Last modified                : 20-05-1998
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-06
  * 
  *  History                      : 23-03-1998 created
  * 
@@ -18,10 +18,10 @@
  */
 
 struct qnx4_sb_info {
-	struct buffer_head *sb_buf;	/* superblock buffer */
-	struct qnx4_super_block *sb;	/* our superblock */
-	unsigned int Version;	/* may be useful */
-	struct qnx4_inode_entry *BitMap;	/* useful */
+	struct buffer_head	*sb_buf;	/* superblock buffer */
+	struct qnx4_super_block	*sb;		/* our superblock */
+	unsigned int		Version;	/* may be useful */
+	struct qnx4_inode_entry	*BitMap;	/* useful */
 };
 
 #endif
diff -u --recursive --new-file v2.3.38/linux/include/linux/qnxtypes.h linux/include/linux/qnxtypes.h
--- v2.3.38/linux/include/linux/qnxtypes.h	Wed Dec 29 13:13:21 1999
+++ linux/include/linux/qnxtypes.h	Mon Jan 10 14:19:46 2000
@@ -2,27 +2,28 @@
  *  Name                         : qnxtypes.h
  *  Author                       : Richard Frowijn
  *  Function                     : standard qnx types
- *  Version                      : 1.0
- *  Last modified                : 22-03-1998
- * 
+ *  Version                      : 1.0.2
+ *  Last modified                : 2000-01-06
+ *
  *  History                      : 22-03-1998 created
- * 
+ *
  */
 
 #ifndef _QNX4TYPES_H
 #define _QNX4TYPES_H
 
-typedef unsigned short qnx4_nxtnt_t;
-typedef unsigned char qnx4_ftype_t;
+typedef __u16 qnx4_nxtnt_t;
+typedef __u8  qnx4_ftype_t;
 
 typedef struct {
-	long xtnt_blk;
-	long xtnt_size;
+	__u32 xtnt_blk;
+	__u32 xtnt_size;
 } qnx4_xtnt_t;
 
-typedef unsigned short qnx4_muid_t;
-typedef unsigned short qnx4_mgid_t;
-typedef unsigned long qnx4_off_t;
-typedef unsigned short qnx4_nlink_t;
+typedef __u16 qnx4_mode_t;
+typedef __u16 qnx4_muid_t;
+typedef __u16 qnx4_mgid_t;
+typedef __u32 qnx4_off_t;
+typedef __u16 qnx4_nlink_t;
 
 #endif
diff -u --recursive --new-file v2.3.38/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.38/linux/include/linux/sched.h	Fri Jan  7 19:13:23 2000
+++ linux/include/linux/sched.h	Mon Jan 10 18:29:22 2000
@@ -274,17 +274,19 @@
 	struct exec_domain *exec_domain;
 	volatile long need_resched;
 
-/* various fields */
+	cycles_t avg_slice;
+	int lock_depth;		/* Lock depth. We can context switch in and out of holding a syscall kernel lock... */	
+/* begin intel cache line */
 	long counter;
 	long priority;
-	cycles_t avg_slice;
-/* SMP and runqueue state */
+	unsigned long policy;
+/* memory management info */
+	struct mm_struct *mm, *active_mm;
 	int has_cpu;
 	int processor;
-	int last_processor;
-	int lock_depth;		/* Lock depth. We can context switch in and out of holding a syscall kernel lock... */	
-	struct task_struct *next_task, *prev_task;
 	struct list_head run_list;
+	struct task_struct *next_task, *prev_task;
+	int last_processor;
 
 /* task state */
 	struct linux_binfmt *binfmt;
@@ -313,7 +315,7 @@
 
 	wait_queue_head_t wait_chldexit;	/* for wait4() */
 	struct semaphore *vfork_sem;		/* for vfork() */
-	unsigned long policy, rt_priority;
+	unsigned long rt_priority;
 	unsigned long it_real_value, it_prof_value, it_virt_value;
 	unsigned long it_real_incr, it_prof_incr, it_virt_incr;
 	struct timer_list real_timer;
@@ -346,10 +348,6 @@
 	struct fs_struct *fs;
 /* open file information */
 	struct files_struct *files;
-
-/* memory management info */
-	struct mm_struct *mm, *active_mm;
-
 /* signal handlers */
 	spinlock_t sigmask_lock;	/* Protects signal and blocked */
 	struct signal_struct *sig;
@@ -398,16 +396,20 @@
  */
 #define INIT_TASK(name) \
 /* state etc */	{ 0,0,0,KERNEL_DS,&default_exec_domain,0, \
-/* counter */	DEF_PRIORITY,DEF_PRIORITY,0, \
-/* SMP */	0,0,0,-1, \
-/* schedlink */	&init_task,&init_task, LIST_HEAD_INIT(init_task.run_list), \
+/* avg_slice */	0, -1, \
+/* counter */	DEF_PRIORITY,DEF_PRIORITY,SCHED_OTHER, \
+/* mm */	NULL, &init_mm, \
+/* has_cpu */	0,0, \
+/* run_list */	LIST_HEAD_INIT(init_task.run_list), \
+/* next_task */	&init_task,&init_task, \
+/* last_proc */	0, \
 /* binfmt */	NULL, \
 /* ec,brk... */	0,0,0,0,0,0, \
 /* pid etc.. */	0,0,0,0,0, \
 /* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
 /* pidhash */	NULL, NULL, \
 /* chld wait */	__WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \
-/* timeout */	SCHED_OTHER,0,0,0,0,0,0,0, \
+/* timeout */	0,0,0,0,0,0,0, \
 /* timer */	{ NULL, NULL, 0, 0, it_real_fn }, \
 /* utime */	{0,0,0,0},0, \
 /* per CPU times */ {0, }, {0, }, \
@@ -426,7 +428,6 @@
 /* thread */	INIT_THREAD, \
 /* fs */	&init_fs, \
 /* files */	&init_files, \
-/* mm */	NULL, &init_mm, \
 /* signals */	SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
 /* exec cts */	0,0, \
 /* exit_sem */	__MUTEX_INITIALIZER(name.exit_sem),	\
@@ -508,10 +509,10 @@
 extern void FASTCALL(wake_up_process(struct task_struct * tsk));
 
 #define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
-#define wake_up_all(x)			__wake_up_all((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
+#define wake_up_all(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
 #define wake_up_sync(x)			__wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
 #define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
-#define wake_up_interruptible_all(x)	__wake_up_all((x),TASK_INTERRUPTIBLE)
+#define wake_up_interruptible_all(x)	__wake_up((x),TASK_INTERRUPTIBLE)
 #define wake_up_interruptible_sync(x)	__wake_up_sync((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
 
 extern int in_group_p(gid_t);
diff -u --recursive --new-file v2.3.38/linux/include/linux/sem.h linux/include/linux/sem.h
--- v2.3.38/linux/include/linux/sem.h	Thu Nov 11 20:11:53 1999
+++ linux/include/linux/sem.h	Mon Jan 10 18:29:05 2000
@@ -19,7 +19,7 @@
 #define SEM_STAT 18
 #define SEM_INFO 19
 
-/* One semid data structure for each set of semaphores in the system. */
+/* Obsolete, used only for backwards compatibility and libc5 compiles */
 struct semid_ds {
 	struct ipc_perm	sem_perm;		/* permissions .. see ipc.h */
 	__kernel_time_t	sem_otime;		/* last semop time */
@@ -31,6 +31,9 @@
 	unsigned short	sem_nsems;		/* no. of semaphores in array */
 };
 
+/* Include the definition of semid64_ds */
+#include <asm/sembuf.h>
+
 /* semop system calls takes an array of these. */
 struct sembuf {
 	unsigned short  sem_num;	/* semaphore index in array */
@@ -81,6 +84,18 @@
 	int	sempid;		/* pid of last operation */
 };
 
+/* One sem_array data structure for each set of semaphores in the system. */
+struct sem_array {
+	struct kern_ipc_perm	sem_perm;	/* permissions .. see ipc.h */
+	time_t			sem_otime;	/* last semop time */
+	time_t			sem_ctime;	/* last change time */
+	struct sem		*sem_base;	/* ptr to first semaphore in array */
+	struct sem_queue	*sem_pending;	/* pending operations to be processed */
+	struct sem_queue	**sem_pending_last; /* last pending operation */
+	struct sem_undo		*undo;		/* undo requests on this array */
+	unsigned long		sem_nsems;	/* no. of semaphores in array */
+};
+
 /* One queue for each sleeping process in the system. */
 struct sem_queue {
 	struct sem_queue *	next;	 /* next entry in the queue */
@@ -89,7 +104,7 @@
 	struct sem_undo *	undo;	 /* undo structure */
 	int    			pid;	 /* process id of requesting process */
 	int    			status;	 /* completion status of operation */
-	struct semid_ds *	sma;	 /* semaphore array for operations */
+	struct sem_array *	sma;	 /* semaphore array for operations */
 	int			id;	 /* internal sem id */
 	struct sembuf *		sops;	 /* array of pending operations */
 	int			nsops;	 /* number of operations */
diff -u --recursive --new-file v2.3.38/linux/include/linux/shm.h linux/include/linux/shm.h
--- v2.3.38/linux/include/linux/shm.h	Sun Nov  7 16:37:34 1999
+++ linux/include/linux/shm.h	Mon Jan 10 18:29:08 2000
@@ -16,9 +16,10 @@
 
 #include <asm/shmparam.h>
 
+/* Obsolete, used only for backwards compatibility and libc5 compiles */
 struct shmid_ds {
 	struct ipc_perm		shm_perm;	/* operation perms */
-	size_t			shm_segsz;	/* size of segment (bytes) */
+	int			shm_segsz;	/* size of segment (bytes) */
 	__kernel_time_t		shm_atime;	/* last attach time */
 	__kernel_time_t		shm_dtime;	/* last detach time */
 	__kernel_time_t		shm_ctime;	/* last change time */
@@ -30,6 +31,9 @@
 	void			*shm_unused3;	/* unused */
 };
 
+/* Include the definition of shmid64_ds and shminfo64 */
+#include <asm/shmbuf.h>
+
 /* permission flag for shmget */
 #define SHM_R		0400	/* or S_IRUGO from <linux/stat.h> */
 #define SHM_W		0200	/* or S_IWUGO from <linux/stat.h> */
@@ -47,8 +51,9 @@
 #define SHM_STAT 	13
 #define SHM_INFO 	14
 
+/* Obsolete, used only for backwards compatibility */
 struct	shminfo {
-	size_t shmmax;
+	int shmmax;
 	int shmmin;
 	int shmmni;
 	int shmseg;
diff -u --recursive --new-file v2.3.38/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v2.3.38/linux/include/linux/smb_fs.h	Wed Aug 18 16:45:22 1999
+++ linux/include/linux/smb_fs.h	Mon Jan 10 18:31:26 2000
@@ -17,6 +17,9 @@
 #define	SMB_IOC_GETMOUNTUID		_IOR('u', 1, __kernel_uid_t)
 #define SMB_IOC_NEWCONN                 _IOW('u', 2, struct smb_conn_opt)
 
+/* __kernel_uid_t can never change, so we have to use __kernel_uid32_t */
+#define	SMB_IOC_GETMOUNTUID32		_IOR('u', 3, __kernel_uid32_t)
+
 #ifdef __KERNEL__
 
 #include <asm/unaligned.h>
diff -u --recursive --new-file v2.3.38/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.38/linux/include/linux/sysctl.h	Thu Jan  6 12:57:48 2000
+++ linux/include/linux/sysctl.h	Mon Jan 10 18:15:58 2000
@@ -108,7 +108,9 @@
  	KERN_MSGMNI=42,		/* int: msg queue identifiers */
  	KERN_SEM=43,		/* struct: sysv semaphore limits */
  	KERN_SPARC_STOP_A=44,	/* int: Sparc Stop-A enable */
- 	KERN_SHMMNI=45		/* int: shm array identifiers */
+ 	KERN_SHMMNI=45,		/* int: shm array identifiers */
+	KERN_OVERFLOWUID=46,	/* int: overflow UID */
+	KERN_OVERFLOWGID=47	/* int: overflow GID */
 };
 
 
@@ -472,7 +474,7 @@
 	NET_DECNET_CONF_DEV_T1 = 2,
 	NET_DECNET_CONF_DEV_T2 = 3,
 	NET_DECNET_CONF_DEV_T3 = 4,
-	NET_DECNET_CONF_DEV_COST = 5,
+	NET_DECNET_CONF_DEV_FORWARDING = 5,
 	NET_DECNET_CONF_DEV_BLKSIZE = 6,
 	NET_DECNET_CONF_DEV_STATE = 7
 };
@@ -491,7 +493,9 @@
 	FS_MAXFILE=7,	/* int:maximum number of filedescriptors that can be allocated */
 	FS_DENTRY=8,
 	FS_NRSUPER=9,	/* int:current number of allocated super_blocks */
-	FS_MAXSUPER=10 	/* int:maximum number of super_blocks that can be allocated */
+	FS_MAXSUPER=10,	/* int:maximum number of super_blocks that can be allocated */
+	FS_OVERFLOWUID=11,	/* int: overflow UID */
+	FS_OVERFLOWGID=12	/* int: overflow GID */
 };
 
 /* CTL_DEBUG names: */
diff -u --recursive --new-file v2.3.38/linux/include/linux/types.h linux/include/linux/types.h
--- v2.3.38/linux/include/linux/types.h	Sun Dec 27 22:18:28 1998
+++ linux/include/linux/types.h	Mon Jan 10 18:29:05 2000
@@ -13,11 +13,27 @@
 typedef __kernel_nlink_t	nlink_t;
 typedef __kernel_off_t		off_t;
 typedef __kernel_pid_t		pid_t;
-typedef __kernel_uid_t		uid_t;
-typedef __kernel_gid_t		gid_t;
 typedef __kernel_daddr_t	daddr_t;
 typedef __kernel_key_t		key_t;
 typedef __kernel_suseconds_t	suseconds_t;
+
+#ifdef __KERNEL__
+typedef __kernel_uid32_t	uid_t;
+typedef __kernel_gid32_t	gid_t;
+typedef __kernel_uid16_t        uid16_t;
+typedef __kernel_gid16_t        gid16_t;
+
+/* libc5 includes this file to define uid_t, thus uid_t can never change
+ * when it is included by non-kernel code
+ */
+#else
+typedef __kernel_uid_t		uid_t;
+typedef __kernel_gid_t		gid_t;
+#endif /* __KERNEL__ */
+
+/* This is defined by include/asm-{arch}/posix_types.h */
+typedef __kernel_old_uid_t	old_uid_t;
+typedef __kernel_old_gid_t	old_gid_t;
 
 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
 typedef __kernel_loff_t		loff_t;
diff -u --recursive --new-file v2.3.38/linux/include/linux/ufs_fs_i.h linux/include/linux/ufs_fs_i.h
--- v2.3.38/linux/include/linux/ufs_fs_i.h	Fri Oct 16 11:53:20 1998
+++ linux/include/linux/ufs_fs_i.h	Mon Jan 10 18:15:58 2000
@@ -22,8 +22,8 @@
 	__u32	i_flags;
 	__u32	i_gen;
 	__u32	i_shadow;
-	__u32	i_uid;
-	__u32	i_gid;
+	__u32	i_unused1;
+	__u32	i_unused2;
 	__u32	i_oeftflag;
 	__u16	i_osync;
 	__u32	i_lastfrag;
diff -u --recursive --new-file v2.3.38/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h
--- v2.3.38/linux/include/linux/umsdos_fs.h	Tue Dec 14 01:27:24 1999
+++ linux/include/linux/umsdos_fs.h	Mon Jan 10 18:31:26 2000
@@ -65,8 +65,8 @@
 	unsigned char name_len;	/* if == 0, then this entry is not used */
 	unsigned char flags;	/* UMSDOS_xxxx */
 	unsigned short nlink;	/* How many hard links point to this entry */
-	uid_t uid;		/* Owner user id */
-	gid_t gid;		/* Group id */
+	__kernel_uid_t uid;	/* Owner user id */
+	__kernel_gid_t gid;	/* Group id */
 	time_t atime;		/* Access time */
 	time_t mtime;		/* Last modification time */
 	time_t ctime;		/* Creation time */
@@ -145,8 +145,8 @@
 		ino_t st_ino;
 		umode_t st_mode;
 		nlink_t st_nlink;
-		uid_t st_uid;
-		gid_t st_gid;
+		__kernel_uid_t st_uid;
+		__kernel_gid_t st_gid;
 		dev_t st_rdev;
 		unsigned short __pad2;
 		off_t st_size;
@@ -158,8 +158,8 @@
 		unsigned long __unused2;
 		time_t st_ctime;
 		unsigned long __unused3;
-		unsigned long __unused4;
-		unsigned long __unused5;
+		uid_t st_uid32;
+		gid_t st_gid32;
 	} stat;
 	char version, release;
 };
diff -u --recursive --new-file v2.3.38/linux/include/linux/usbdev_fs_i.h linux/include/linux/usbdev_fs_i.h
--- v2.3.38/linux/include/linux/usbdev_fs_i.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/usbdev_fs_i.h	Mon Jan 10 11:32:48 2000
@@ -0,0 +1,11 @@
+struct usb_device;
+struct usb_bus;
+
+struct usbdev_inode_info {
+	struct list_head dlist;
+	struct list_head slist;
+	union {
+		struct usb_device *dev;
+		struct usb_bus *bus;
+	} p;
+};
diff -u --recursive --new-file v2.3.38/linux/include/linux/usbdev_fs_sb.h linux/include/linux/usbdev_fs_sb.h
--- v2.3.38/linux/include/linux/usbdev_fs_sb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/usbdev_fs_sb.h	Mon Jan 10 11:32:48 2000
@@ -0,0 +1,10 @@
+struct usbdev_sb_info {
+	struct list_head slist;
+	struct list_head ilist;
+	uid_t devuid;
+	gid_t devgid;
+	umode_t devmode;
+	uid_t busuid;
+	gid_t busgid;
+	umode_t busmode;
+};
diff -u --recursive --new-file v2.3.38/linux/include/net/dn.h linux/include/net/dn.h
--- v2.3.38/linux/include/net/dn.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/dn.h	Mon Jan 10 18:29:56 2000
@@ -120,7 +120,6 @@
 
 /*
  * src,dst : Source and Destination DECnet addresses
- * neigh: Address from which we've just got this skb.
  * hops : Number of hops through the network
  * dst_port, src_port : NSP port numbers
  * services, info : Useful data extracted from conninit messages
@@ -134,13 +133,12 @@
  *
  * As a general policy, this structure keeps all addresses in network
  * byte order, and all else in host byte order. Thus dst, src, dst_port
- * src_port and neigh are in network order. All else is in host order.
+ * and src_port are in network order. All else is in host order.
  * 
  */
 struct dn_skb_cb {
 	unsigned short dst;
 	unsigned short src;
-	unsigned short neigh;
 	unsigned short hops;
 	unsigned short dst_port;
 	unsigned short src_port;
@@ -184,7 +182,7 @@
 extern struct sock *dn_find_by_skb(struct sk_buff *skb);
 #define DN_ASCBUF_LEN 7
 extern char *dn_addr2asc(dn_address, char *);
-extern void dn_destroy_sock(struct sock *sk);
+extern int dn_destroy_timer(struct sock *sk);
 
 extern int dn_sockaddr2username(struct sockaddr_dn *addr, unsigned char *buf, unsigned char type);
 extern int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *addr, unsigned char *type);
@@ -196,7 +194,6 @@
 
 extern dn_address decnet_address;
 extern unsigned char decnet_ether_address[6];
-extern int decnet_node_type;
 extern int decnet_debug_level;
 extern int decnet_time_wait;
 extern int decnet_dn_count;
diff -u --recursive --new-file v2.3.38/linux/include/net/dn_dev.h linux/include/net/dn_dev.h
--- v2.3.38/linux/include/net/dn_dev.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/dn_dev.h	Sat Jan  8 21:36:20 2000
@@ -45,10 +45,11 @@
  * device will come up. In the dn_dev structure, it is the actual
  * state.
  *
- * The cost field is used in the routing algorithm.
+ * Things have changed here. I've killed timer1 since its a user space
+ * issue for a user space routing deamon to sort out. The kernel does
+ * not need to be bothered with it.
  *
  * Timers:
- * t1 - Routing timer, send routing messages when it expires
  * t2 - Rate limit timer, min time between routing and hello messages
  * t3 - Hello timer, send hello messages when it expires
  *
@@ -56,30 +57,27 @@
  * up() - Called to initialize device, return value can veto use of
  *        device with DECnet.
  * down() - Called to turn device off when it goes down
- * timer1() - Called when timer 1 goes off
  * timer3() - Called when timer 3 goes off
  * 
  * sysctl - Hook for sysctl things
  *
  */
 struct dn_dev_parms {
-	int type;	          /* ARPHRD_xxx                     */
-	int mode;	          /* Broadcast, Unicast, Mulitpoint */
+	int type;	          /* ARPHRD_xxx                         */
+	int mode;	          /* Broadcast, Unicast, Mulitpoint     */
 #define DN_DEV_BCAST  1
 #define DN_DEV_UCAST  2
 #define DN_DEV_MPOINT 4
-	int state;                /* Initial state                  */
-	int cost;	          /* Default cost of device         */
-	unsigned short blksize;   /* Block Size                     */
-	unsigned long t1;         /* Default value of t1            */
-	unsigned long t2;         /* Default value of t2            */
-	unsigned long t3;         /* Default value of t3            */
-	int priority;             /* Priority to be a router        */
-	char *name;               /* Name for sysctl                */
-	int ctl_name;             /* Index for sysctl               */
+	int state;                /* Initial state                      */
+	int forwarding;	          /* 0=EndNode, 1=L1Router, 2=L2Router  */
+	unsigned short blksize;   /* Block Size                         */
+	unsigned long t2;         /* Default value of t2                */
+	unsigned long t3;         /* Default value of t3                */
+	int priority;             /* Priority to be a router            */
+	char *name;               /* Name for sysctl                    */
+	int ctl_name;             /* Index for sysctl                   */
 	int  (*up)(struct net_device *);
 	void (*down)(struct net_device *);
-	void (*timer1)(struct net_device *);
 	void (*timer3)(struct net_device *);
 	void *sysctl;
 };
@@ -91,7 +89,7 @@
 	struct dn_dev_parms parms;
 	char use_long;
         struct timer_list timer;
-        unsigned long t3, t1;
+        unsigned long t3;
 	struct neigh_parms *neigh_parms;
 	unsigned char addr[ETH_ALEN];
 	struct neighbour *router; /* Default router on circuit */
@@ -124,33 +122,34 @@
 
 /*------------------------- DRP - Routing messages ---------------------*/
 
-        struct endnode_hello_message
-        {
-                unsigned char   msgflg          __attribute__((packed));
-                unsigned char   tiver[3]        __attribute__((packed));
-                unsigned char   id[6]           __attribute__((packed));
-                unsigned char   iinfo           __attribute__((packed));
-                unsigned short  blksize         __attribute__((packed));
-                unsigned char   area            __attribute__((packed));
-                unsigned char   seed[8]         __attribute__((packed));
-                unsigned char   neighbor[6]     __attribute__((packed));
-                unsigned short  timer           __attribute__((packed));
-                unsigned char   mpd             __attribute__((packed));
-                unsigned char   datalen         __attribute__((packed));
-                unsigned char   data[2]         __attribute__((packed));
-        };
-        struct rtnode_hello_message
-        {
-                unsigned char   msgflg          __attribute__((packed));
-                unsigned char   tiver[3]        __attribute__((packed));
-                unsigned char   id[6]           __attribute__((packed));
-                unsigned char   iinfo           __attribute__((packed));
-                unsigned short  blksize         __attribute__((packed));
-                unsigned char   priority        __attribute__((packed));
-                unsigned char   area            __attribute__((packed));
-                unsigned short  timer           __attribute__((packed));
-                unsigned char   mpd             __attribute__((packed));
-        };
+struct endnode_hello_message
+{
+	unsigned char   msgflg          __attribute__((packed));
+        unsigned char   tiver[3]        __attribute__((packed));
+        unsigned char   id[6]           __attribute__((packed));
+        unsigned char   iinfo           __attribute__((packed));
+        unsigned short  blksize         __attribute__((packed));
+        unsigned char   area            __attribute__((packed));
+        unsigned char   seed[8]         __attribute__((packed));
+        unsigned char   neighbor[6]     __attribute__((packed));
+        unsigned short  timer           __attribute__((packed));
+        unsigned char   mpd             __attribute__((packed));
+        unsigned char   datalen         __attribute__((packed));
+        unsigned char   data[2]         __attribute__((packed));
+};
+
+struct rtnode_hello_message
+{
+	unsigned char   msgflg          __attribute__((packed));
+        unsigned char   tiver[3]        __attribute__((packed));
+        unsigned char   id[6]           __attribute__((packed));
+        unsigned char   iinfo           __attribute__((packed));
+        unsigned short  blksize         __attribute__((packed));
+        unsigned char   priority        __attribute__((packed));
+        unsigned char   area            __attribute__((packed));
+        unsigned short  timer           __attribute__((packed));
+        unsigned char   mpd             __attribute__((packed));
+};
 
 
 extern void dn_dev_init(void);
diff -u --recursive --new-file v2.3.38/linux/include/net/dn_fib.h linux/include/net/dn_fib.h
--- v2.3.38/linux/include/net/dn_fib.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/dn_fib.h	Sat Jan  8 21:36:20 2000
@@ -5,81 +5,203 @@
 
 #ifdef CONFIG_DECNET_ROUTER
 
+#include <linux/rtnetlink.h>
+
+struct dn_kern_rta
+{
+        void            *rta_dst;
+        void            *rta_src;
+        int             *rta_iif;
+        int             *rta_oif;
+        void            *rta_gw;
+        u32             *rta_priority;
+        void            *rta_prefsrc;
+        struct rtattr   *rta_mx;
+        struct rtattr   *rta_mp;
+        unsigned char   *rta_protoinfo;
+        unsigned char   *rta_flow;
+        struct rta_cacheinfo *rta_ci;
+};
+
+struct dn_fib_key {
+	dn_address src;
+	dn_address dst;
+	int iif;
+	int oif;
+	u32 fwmark;
+	unsigned char scope;
+};
 
 struct dn_fib_res {
-	dn_address res_addr;
-	dn_address res_mask;
-	int res_ifindex;
-	int res_proto;
-	int res_cost;
-	int res_type;
-	struct dn_fib_node *res_fn;
-	struct dn_fib_action *res_fa;
-};
-
-struct dn_fib_action {
-	struct dn_fib_action *fa_next;
-	dn_address fa_key;
-	dn_address fa_mask;
-	int fa_ifindex;
-	int fa_proto;
-	int fa_cost;
-	int fa_type;
-	union {
-		struct neighbour *fau_neigh;	/* Normal route */
-		int fau_error;			/* Reject       */
-		int fau_table;			/* Throw        */
-	} fa_u;
-#define fa_neigh fa_u.fau_neigh
-#define fa_error fa_u.fau_error
-#define fa_table fa_u.fau_table
+	struct dn_fib_rule *r;
+	struct dn_fib_info *fi;
+	unsigned char prefixlen;
+	unsigned char nh_sel;
+	unsigned char type;
+	unsigned char scope;
 };
 
-struct dn_fib_node {
-	struct dn_fib_node *fn_up;
-	dn_address fn_cmpmask;
-	dn_address fn_key;
-	int fn_shift;
-	struct dn_fib_action *fn_action;
-	struct dn_fib_node *fn_children[2];
+struct dn_fib_nh {
+	struct net_device	*nh_dev;
+	unsigned		nh_flags;
+	unsigned char		nh_scope;
+	int			nh_weight;
+	int			nh_power;
+	int			nh_oif;
+	u32			nh_gw;
+};
+
+struct dn_fib_info {
+	struct dn_fib_info	*fib_next;
+	struct dn_fib_info	*fib_prev;
+	int 			fib_treeref;
+	atomic_t		fib_clntref;
+	int			fib_dead;
+	unsigned		fib_flags;
+	int			fib_protocol;
+	dn_address		fib_prefsrc;
+	u32			fib_priority;
+	int			fib_nhs;
+	int			fib_power;
+	struct dn_fib_nh	fib_nh[0];
+#define fib_dev		fib_nh[0].nh_dev
 };
 
-#define DN_FIB_NEXT(fibnode, key) ((fibnode)->fn_children[((key) ^ (fibnode)->fn_cmpmask) >> (fibnode)->fn_shift]) 
 
-struct dn_fib_walker_t;
+#define DN_FIB_RES_NH(res)	((res).fi->fib_nh[(res).nh_sel])
+#define DN_FIB_RES_RESET(res)	((res).nh_sel = 0)
+#define DN_FIB_RES_GW(res)	(DN_FIB_RES_NH(res).nh_gw)
+#define DN_FIB_RES_DEV(res)	(DN_FIB_RES_NH(res).nh_dev)
+#define DN_FIB_RES_OIF(res)	(DN_FIB_RES_NH(res).nh_oif)
+
+typedef struct {
+	u16	datum;
+} dn_fib_key_t;
+
+typedef struct {
+	u16	datum;
+} dn_fib_hash_t;
+
+typedef struct {
+	u16	datum;
+} dn_fib_idx_t;
+
+struct dn_fib_node {
+	struct dn_fib_node *fn_next;
+	struct dn_fib_info *fn_info;
+#define DN_FIB_INFO(f) ((f)->fn_info)
+	dn_fib_key_t	fn_key;
+	u8		fn_type;
+	u8		fn_scope;
+	u8		fn_state;
+};
+
 
 struct dn_fib_table {
 	int n;
-	unsigned long count;
-	struct dn_fib_node *root;
 
-	int (*insert)(struct dn_fib_table *t, struct dn_fib_action *fa);
-	int (*delete)(struct dn_fib_table *t, struct dn_fib_action *fa);
-	int (*lookup)(struct dn_fib_table *t, struct dn_fib_res *res);
-	int (*walk)(struct dn_fib_walker_t *fwt);
+	int (*insert)(struct dn_fib_table *t, struct rtmsg *r, 
+			struct dn_kern_rta *rta, struct nlmsghdr *n, 
+			struct netlink_skb_parms *req);
+	int (*delete)(struct dn_fib_table *t, struct rtmsg *r,
+			struct dn_kern_rta *rta, struct nlmsghdr *n,
+			struct netlink_skb_parms *req);
+	int (*lookup)(struct dn_fib_table *t, const struct dn_fib_key *key, 
+			struct dn_fib_res *res);
+	int (*flush)(struct dn_fib_table *t);
+#ifdef CONFIG_PROC_FS
+	int (*get_info)(struct dn_fib_table *table, char *buf,
+			int first, int count);
+#endif /* CONFIG_PROC_FS */
 #ifdef CONFIG_RTNETLINK
 	int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
 #endif /* CONFIG_RTNETLINK */
-};
 
-struct dn_fib_walker_t {
-	struct dn_fib_table *table;
-	void *arg;
-	int (*fxn)(struct dn_fib_walker_t *fwt, struct dn_fib_node *n);
+	unsigned char data[0];
 };
 
+
+/*
+ * dn_fib.c
+ */
 extern void dn_fib_init(void);
 extern void dn_fib_cleanup(void);
 
 extern int dn_fib_rt_message(struct sk_buff *skb);
-extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
-extern int dn_fib_resolve(struct dn_fib_res *res);
-
+extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd, 
+			unsigned long arg);
+extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, 
+				struct dn_kern_rta *rta, 
+				const struct nlmsghdr *nlh, int *errp);
+extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi, 
+			const struct dn_fib_key *key, struct dn_fib_res *res);
+extern void dn_fib_release_info(struct dn_fib_info *fi);
+extern u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type);
+extern void dn_fib_flush(void);
+extern void dn_fib_select_multipath(const struct dn_fib_key *key, 
+					struct dn_fib_res *res);
+extern int dn_fib_sync_down(dn_address local, struct net_device *dev, 
+				int force);
+extern int dn_fib_sync_up(struct net_device *dev);
+
+/*
+ * dn_tables.c
+ */
+extern struct dn_fib_table *dn_fib_get_table(int n, int creat);
+extern struct dn_fib_table *dn_fib_empty_table(void);
+extern void dn_fib_table_init(void);
+extern void dn_fib_table_cleanup(void);
+
+/*
+ * dn_rules.c
+ */
+extern void dn_fib_rules_init(void);
+extern void dn_fib_rules_cleanup(void);
+extern void dn_fib_rule_put(struct dn_fib_rule *);
+extern int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res);
+
+/*
+ * rtnetlink interface
+ */
 #ifdef CONFIG_RTNETLINK
 extern int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
 extern int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb);
+
+extern int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
+extern int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
+extern int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb);
 #endif /* CONFIG_RTNETLINK */
+
+#define DN_NUM_TABLES 255
+#define DN_MIN_TABLE 1
+#define DN_DEFAULT_TABLE 1
+#define DN_L1_TABLE 1
+#define DN_L2_TABLE 2
+
+extern void dn_fib_free_info(struct dn_fib_info *fi);
+
+static __inline__ void dn_fib_info_put(struct dn_fib_info *fi)
+{
+	if (atomic_dec_and_test(&fi->fib_clntref))
+		dn_fib_free_info(fi);
+}
+
+static __inline__ void dn_fib_res_put(struct dn_fib_res *res)
+{
+	if (res->fi)
+		dn_fib_info_put(res->fi);
+	if (res->r)
+		dn_fib_rule_put(res->r);
+}
+
+static __inline__ u16 dnet_make_mask(int n)
+{
+        if (n)
+                return htons(~((1<<(16-n))-1));
+        return 0;
+}
+
 #endif /* CONFIG_DECNET_ROUTER */
 
 #endif /* _NET_DN_FIB_H */
diff -u --recursive --new-file v2.3.38/linux/include/net/dn_nsp.h linux/include/net/dn_nsp.h
--- v2.3.38/linux/include/net/dn_nsp.h	Wed May 26 09:36:35 1999
+++ linux/include/net/dn_nsp.h	Sat Jan  8 21:36:20 2000
@@ -19,8 +19,11 @@
 extern void dn_nsp_send_oth_ack(struct sock *sk);
 extern void dn_nsp_delayed_ack(struct sock *sk);
 extern void dn_send_conn_ack(struct sock *sk);
-extern void dn_send_conn_conf(struct sock *sk);
-extern void dn_send_disc(struct sock *sk, unsigned char type, unsigned short reason);
+extern void dn_send_conn_conf(struct sock *sk, int gfp);
+extern void dn_nsp_send_disc(struct sock *sk, unsigned char type, 
+				unsigned short reason, int gfp);
+extern void dn_nsp_return_disc(struct sk_buff *skb, unsigned char type,
+				unsigned short reason);
 extern void dn_nsp_send_lnk(struct sock *sk, unsigned short flags);
 extern void dn_nsp_send_conninit(struct sock *sk, unsigned char flags);
 
@@ -49,88 +52,79 @@
 
 /* Data Messages    (data segment/interrupt/link service)               */
 
-        struct nsp_data_seg_msg
-        {
-                unsigned char   msgflg          __attribute__((packed));
-                unsigned short  dstaddr         __attribute__((packed));
-                unsigned short  srcaddr         __attribute__((packed));
-        };
-
-        struct nsp_data_opt_msg
-        {
-                unsigned short  acknum          __attribute__((packed));
-                unsigned short  segnum          __attribute__((packed));
-                unsigned short  lsflgs          __attribute__((packed));
-        };
-
-        struct nsp_data_opt_msg1
-        {
-                unsigned short  acknum          __attribute__((packed));
-                unsigned short  segnum          __attribute__((packed));
-        };
-
-/* Acknowledgment Messages */
-/*-------------------------*/
-
-/* Acknowledgment Messages (data/other data)                             */
-
-        struct  nsp_data_ack_msg
-        {
-                unsigned char   msgflg          __attribute__((packed));
-                unsigned short  dstaddr         __attribute__((packed));
-                unsigned short  srcaddr         __attribute__((packed));
-                unsigned short  acknum          __attribute__((packed));
-        };
+struct nsp_data_seg_msg
+{
+	unsigned char   msgflg          __attribute__((packed));
+	unsigned short  dstaddr         __attribute__((packed));
+	unsigned short  srcaddr         __attribute__((packed));
+};
+
+struct nsp_data_opt_msg
+{
+	unsigned short  acknum          __attribute__((packed));
+	unsigned short  segnum          __attribute__((packed));
+	unsigned short  lsflgs          __attribute__((packed));
+};
+
+struct nsp_data_opt_msg1
+{
+	unsigned short  acknum          __attribute__((packed));
+	unsigned short  segnum          __attribute__((packed));
+};
+
+
+/* Acknowledgment Message (data/other data)                             */
+struct nsp_data_ack_msg
+{
+	unsigned char   msgflg          __attribute__((packed));
+	unsigned short  dstaddr         __attribute__((packed));
+	unsigned short  srcaddr         __attribute__((packed));
+	unsigned short  acknum          __attribute__((packed));
+};
 
 /* Connect Acknowledgment Message */
+struct  nsp_conn_ack_msg
+{
+	unsigned char   msgflg          __attribute__((packed));
+	unsigned short  dstaddr         __attribute__((packed));
+};
 
-        struct  nsp_conn_ack_msg
-        {
-                unsigned char   msgflg          __attribute__((packed));
-                unsigned short  dstaddr         __attribute__((packed));
-        };
-
-/* Control Messages */
-/*------------------*/
 
 /* Connect Initiate/Retransmit Initiate/Connect Confirm */
-
-        struct  nsp_conn_init_msg
-        {
-                unsigned char   msgflg          __attribute__((packed));
-#define         NSP_CI          0x18            /* Connect Initiate     */
-#define         NSP_RCI         0x68            /* Retrans. Conn Init   */
-                unsigned short  dstaddr         __attribute__((packed));
-                unsigned short  srcaddr         __attribute__((packed));
-                unsigned char   services        __attribute__((packed));
-#define         NSP_FC_NONE     0x00            /* Flow Control None    */
-#define         NSP_FC_SRC      0x04            /* Seg Req. Count       */
-#define         NSP_FC_SCMC     0x08            /* Sess. Control Mess   */
-                unsigned char   info            __attribute__((packed));
-                unsigned short  segsize         __attribute__((packed));
-        };
+struct  nsp_conn_init_msg
+{
+	unsigned char   msgflg          __attribute__((packed));
+#define NSP_CI      0x18            /* Connect Initiate     */
+#define NSP_RCI     0x68            /* Retrans. Conn Init   */
+	unsigned short  dstaddr         __attribute__((packed));
+        unsigned short  srcaddr         __attribute__((packed));
+        unsigned char   services        __attribute__((packed));
+#define NSP_FC_NONE   0x00            /* Flow Control None    */
+#define NSP_FC_SRC    0x04            /* Seg Req. Count       */
+#define NSP_FC_SCMC   0x08            /* Sess. Control Mess   */
+	unsigned char   info            __attribute__((packed));
+        unsigned short  segsize         __attribute__((packed));
+};
 
 /* Disconnect Initiate/Disconnect Confirm */
+struct  nsp_disconn_init_msg
+{
+	unsigned char   msgflg          __attribute__((packed));
+        unsigned short  dstaddr         __attribute__((packed));
+        unsigned short  srcaddr         __attribute__((packed));
+        unsigned short  reason          __attribute__((packed));
+};
+
+
 
-        struct  nsp_disconn_init_msg
-        {
-                unsigned char   msgflg          __attribute__((packed));
-                unsigned short  dstaddr         __attribute__((packed));
-                unsigned short  srcaddr         __attribute__((packed));
-                unsigned short  reason          __attribute__((packed));
-        };
-
-
-/*------------------------- SCP - messages ------------------------------*/
-
-        struct  srcobj_fmt
-        {
-                char            format          __attribute__((packed));
-                unsigned char   task            __attribute__((packed));
-                unsigned short  grpcode         __attribute__((packed));
-                unsigned short  usrcode         __attribute__((packed));
-                char            dlen            __attribute__((packed));
-        };
+struct  srcobj_fmt
+{
+	char            format          __attribute__((packed));
+        unsigned char   task            __attribute__((packed));
+        unsigned short  grpcode         __attribute__((packed));
+        unsigned short  usrcode         __attribute__((packed));
+        char            dlen            __attribute__((packed));
+};
 
 /*
  * A collection of functions for manipulating the sequence
diff -u --recursive --new-file v2.3.38/linux/include/net/dn_route.h linux/include/net/dn_route.h
--- v2.3.38/linux/include/net/dn_route.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/dn_route.h	Sat Jan  8 21:36:20 2000
@@ -19,6 +19,8 @@
 extern int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags);
 extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
 extern int dn_cache_getroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
+extern void dn_rt_cache_flush(int delay);
+
 /* Masks for flags field */
 #define DN_RT_F_PID 0x07 /* Mask for packet type                      */
 #define DN_RT_F_PF  0x80 /* Padding Follows                           */
@@ -56,16 +58,31 @@
 #define DN_RT_INFO_NOML 0x20 /* No Multicast traffic accepted */
 #define DN_RT_INFO_BLKR 0x40 /* Blocking Requested            */
 
-
+/*
+ * The key structure is what we used to look up the route.
+ * The rt_saddr & rt_daddr entries are the same as key.saddr & key.daddr
+ * except for local input routes, where the rt_saddr = key.daddr and
+ * rt_daddr = key.saddr to allow the route to be used for returning
+ * packets to the originating host.
+ */
 struct dn_route {
 	union {
 		struct dst_entry dst;
 		struct dn_route *rt_next;
 	} u;
+	struct {
+		unsigned short saddr;
+		unsigned short daddr;
+		int iif;
+		int oif;
+		u32 fwmark;
+	} key;
 	unsigned short rt_saddr;
 	unsigned short rt_daddr;
-	int rt_iif;
-	int rt_oif;
+	unsigned char rt_type;
+	unsigned char rt_scope;
+	unsigned char rt_protocol;
+	unsigned char rt_table;
 };
 
 extern void dn_route_init(void);
diff -u --recursive --new-file v2.3.38/linux/include/net/icmp.h linux/include/net/icmp.h
--- v2.3.38/linux/include/net/icmp.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/icmp.h	Mon Jan 10 18:30:44 2000
@@ -25,7 +25,10 @@
 #include <net/protocol.h>
 
 extern struct icmp_err icmp_err_convert[];
-extern struct icmp_mib icmp_statistics;
+extern struct icmp_mib icmp_statistics[NR_CPUS*2];
+#define ICMP_INC_STATS(field)		SNMP_INC_STATS(icmp_statistics, field)
+#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);
diff -u --recursive --new-file v2.3.38/linux/include/net/ip.h linux/include/net/ip.h
--- v2.3.38/linux/include/net/ip.h	Thu Jan  6 12:57:48 2000
+++ linux/include/net/ip.h	Mon Jan 10 18:30:44 2000
@@ -147,10 +147,17 @@
 };
 
 extern struct ipv4_config ipv4_config;
-extern struct ip_mib	ip_statistics;
-extern struct linux_mib	net_statistics;
+extern struct ip_mib	ip_statistics[NR_CPUS*2];
+#define IP_INC_STATS(field)		SNMP_INC_STATS(ip_statistics, field)
+#define IP_INC_STATS_BH(field)		SNMP_INC_STATS_BH(ip_statistics, field)
+#define IP_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(ip_statistics, field)
+extern struct linux_mib	net_statistics[NR_CPUS*2];
+#define NET_INC_STATS(field)		SNMP_INC_STATS(net_statistics, field)
+#define NET_INC_STATS_BH(field)		SNMP_INC_STATS_BH(net_statistics, field)
+#define NET_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(net_statistics, field)
 
 extern int sysctl_local_port_range[2];
+extern int sysctl_ip_default_ttl;
 
 #ifdef CONFIG_INET
 extern __inline__ int ip_send(struct sk_buff *skb)
diff -u --recursive --new-file v2.3.38/linux/include/net/ipv6.h linux/include/net/ipv6.h
--- v2.3.38/linux/include/net/ipv6.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/ipv6.h	Mon Jan 10 18:30:38 2000
@@ -4,7 +4,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: ipv6.h,v 1.18 1999/08/20 11:00:53 davem Exp $
+ *	$Id: ipv6.h,v 1.19 2000/01/09 02:19:26 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -86,9 +86,18 @@
 
 #include <net/sock.h>
 
-extern struct ipv6_mib		ipv6_statistics;
-extern struct icmpv6_mib	icmpv6_statistics;
-extern struct udp_mib		udp_stats_in6;
+extern struct ipv6_mib		ipv6_statistics[NR_CPUS*2];
+#define IP6_INC_STATS(field)		SNMP_INC_STATS(ipv6_statistics, field)
+#define IP6_INC_STATS_BH(field)		SNMP_INC_STATS_BH(ipv6_statistics, field)
+#define IP6_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(ipv6_statistics, field)
+extern struct icmpv6_mib	icmpv6_statistics[NR_CPUS*2];
+#define ICMP6_INC_STATS(field)		SNMP_INC_STATS(icmpv6_statistics, field)
+#define ICMP6_INC_STATS_BH(field)	SNMP_INC_STATS_BH(icmpv6_statistics, field)
+#define ICMP6_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(icmpv6_statistics, field)
+extern struct udp_mib		udp_stats_in6[NR_CPUS*2];
+#define UDP6_INC_STATS(field)		SNMP_INC_STATS(udp_stats_in6, field)
+#define UDP6_INC_STATS_BH(field)	SNMP_INC_STATS_BH(udp_stats_in6, field)
+#define UDP6_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(udp_stats_in6, field)
 extern atomic_t			inet6_sock_nr;
 
 struct ip6_ra_chain
diff -u --recursive --new-file v2.3.38/linux/include/net/pkt_sched.h linux/include/net/pkt_sched.h
--- v2.3.38/linux/include/net/pkt_sched.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/pkt_sched.h	Sat Jan  8 12:56:30 2000
@@ -81,6 +81,7 @@
 	unsigned		flags;
 #define TCQ_F_BUILTIN	1
 #define TCQ_F_THROTTLED	2
+#define TCQ_F_INGRES	4
 	struct Qdisc_ops	*ops;
 	struct Qdisc		*next;
 	u32			handle;
diff -u --recursive --new-file v2.3.38/linux/include/net/snmp.h linux/include/net/snmp.h
--- v2.3.38/linux/include/net/snmp.h	Sun Oct  4 10:19:39 1998
+++ linux/include/net/snmp.h	Sat Jan  8 21:36:20 2000
@@ -27,8 +27,6 @@
   
 struct ip_mib
 {
- 	unsigned long	IpForwarding;
- 	unsigned long	IpDefaultTTL;
  	unsigned long	IpInReceives;
  	unsigned long	IpInHdrErrors;
  	unsigned long	IpInAddrErrors;
@@ -46,6 +44,7 @@
  	unsigned long	IpFragOKs;
  	unsigned long	IpFragFails;
  	unsigned long	IpFragCreates;
+	unsigned long	__pad[32-19];
 };
  
 struct ipv6_mib
@@ -72,6 +71,7 @@
  	unsigned long	Ip6FragCreates;
  	unsigned long	Ip6InMcastPkts;
  	unsigned long	Ip6OutMcastPkts;
+	unsigned long	__pad[32-22];
 };
  
 struct icmp_mib
@@ -102,6 +102,7 @@
  	unsigned long	IcmpOutTimestampReps;
  	unsigned long	IcmpOutAddrMasks;
  	unsigned long	IcmpOutAddrMaskReps;
+	unsigned long	__pad[32-26];
 };
 
 struct icmpv6_mib
@@ -139,6 +140,7 @@
 	unsigned long	Icmp6OutRedirects;
 	unsigned long	Icmp6OutGroupMembResponses;
 	unsigned long	Icmp6OutGroupMembReductions;
+	unsigned long	__pad[32-28];
 };
  
 struct tcp_mib
@@ -157,6 +159,7 @@
  	unsigned long	TcpRetransSegs;
  	unsigned long	TcpInErrs;
  	unsigned long	TcpOutRsts;
+	unsigned long	__pad[16-14];
 };
  
 struct udp_mib
@@ -165,6 +168,7 @@
  	unsigned long	UdpNoPorts;
  	unsigned long	UdpInErrors;
  	unsigned long	UdpOutDatagrams;
+	unsigned long	__pad[0];
 };
 
 struct linux_mib 
@@ -178,6 +182,11 @@
 	unsigned long	OfoPruned;
 	unsigned long	OutOfWindowIcmps; 
 	unsigned long	LockDroppedIcmps; 
+	unsigned long	__pad[32-9];
 };
+
+#define SNMP_INC_STATS(mib, field) ((mib)[2*smp_processor_id()+!in_interrupt()].field++)
+#define SNMP_INC_STATS_BH(mib, field) ((mib)[2*smp_processor_id()].field++)
+#define SNMP_INC_STATS_USER(mib, field) ((mib)[2*smp_processor_id()+1].field++)
  	
 #endif
diff -u --recursive --new-file v2.3.38/linux/include/net/sock.h linux/include/net/sock.h
--- v2.3.38/linux/include/net/sock.h	Tue Dec  7 09:32:51 1999
+++ linux/include/net/sock.h	Mon Jan 10 18:30:37 2000
@@ -635,9 +635,23 @@
 	unsigned short		max_header;
 	unsigned long		retransmits;
 	char			name[32];
-	int			inuse, highestinuse;
+
+	struct {
+		int inuse;
+		u8  __pad[SMP_CACHE_BYTES - sizeof(int)];
+	} stats[NR_CPUS];
 };
 
+/* Called with local bh disabled */
+static void __inline__ sock_prot_inc_use(struct proto *prot)
+{
+	prot->stats[smp_processor_id()].inuse++;
+}
+
+static void __inline__ sock_prot_dec_use(struct proto *prot)
+{
+	prot->stats[smp_processor_id()].inuse--;
+}
 
 /* About 10 seconds */
 #define SOCK_DESTROY_TIME (10*HZ)
@@ -731,6 +745,7 @@
 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
diff -u --recursive --new-file v2.3.38/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.3.38/linux/include/net/tcp.h	Fri Sep 10 23:57:37 1999
+++ linux/include/net/tcp.h	Mon Jan 10 18:30:46 2000
@@ -488,7 +488,11 @@
 
 
 extern struct proto tcp_prot;
-extern struct tcp_mib tcp_statistics;
+
+extern struct tcp_mib tcp_statistics[NR_CPUS*2];
+#define TCP_INC_STATS(field)		SNMP_INC_STATS(tcp_statistics, field)
+#define TCP_INC_STATS_BH(field)		SNMP_INC_STATS_BH(tcp_statistics, field)
+#define TCP_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(tcp_statistics, field)
 
 extern void			tcp_put_port(struct sock *sk);
 extern void			__tcp_put_port(struct sock *sk);
@@ -980,7 +984,7 @@
 	switch (state) {
 	case TCP_ESTABLISHED:
 		if (oldstate != TCP_ESTABLISHED)
-			tcp_statistics.TcpCurrEstab++;
+			TCP_INC_STATS(TcpCurrEstab);
 		break;
 
 	case TCP_CLOSE:
@@ -988,7 +992,7 @@
 		/* fall through */
 	default:
 		if (oldstate==TCP_ESTABLISHED)
-			tcp_statistics.TcpCurrEstab--;
+			tcp_statistics[smp_processor_id()*2+!in_interrupt()].TcpCurrEstab--;
 	}
 
 	/* Change state AFTER socket is unhashed to avoid closed
diff -u --recursive --new-file v2.3.38/linux/include/net/udp.h linux/include/net/udp.h
--- v2.3.38/linux/include/net/udp.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/udp.h	Mon Jan 10 18:30:38 2000
@@ -69,4 +69,9 @@
 extern int	udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
 extern int	udp_disconnect(struct sock *sk, int flags);
 
+extern struct udp_mib udp_statistics[NR_CPUS*2];
+#define UDP_INC_STATS(field)		SNMP_INC_STATS(udp_statistics, field)
+#define UDP_INC_STATS_BH(field)		SNMP_INC_STATS_BH(udp_statistics, field)
+#define UDP_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(udp_statistics, field)
+
 #endif	/* _UDP_H */
diff -u --recursive --new-file v2.3.38/linux/ipc/msg.c linux/ipc/msg.c
--- v2.3.38/linux/ipc/msg.c	Thu Nov 11 20:11:54 1999
+++ linux/ipc/msg.c	Mon Jan 10 18:15:58 2000
@@ -66,15 +66,15 @@
 
 /* one msq_queue structure for each present queue on the system */
 struct msg_queue {
-	struct ipc_perm q_perm;
-	__kernel_time_t q_stime;	/* last msgsnd time */
-	__kernel_time_t q_rtime;	/* last msgrcv time */
-	__kernel_time_t q_ctime;	/* last change time */
-	unsigned int  q_cbytes;		/* current number of bytes on queue */
-	unsigned int  q_qnum;		/* number of messages in queue */
-	unsigned int  q_qbytes;		/* max number of bytes on queue */
-	__kernel_ipc_pid_t q_lspid;	/* pid of last msgsnd */
-	__kernel_ipc_pid_t q_lrpid;	/* last receive pid */
+	struct kern_ipc_perm q_perm;
+	time_t q_stime;			/* last msgsnd time */
+	time_t q_rtime;			/* last msgrcv time */
+	time_t q_ctime;			/* last change time */
+	unsigned long q_cbytes;		/* current number of bytes on queue */
+	unsigned long q_qnum;		/* number of messages in queue */
+	unsigned long q_qbytes;		/* max number of bytes on queue */
+	pid_t q_lspid;			/* pid of last msgsnd */
+	pid_t q_lrpid;			/* last receive pid */
 
 	struct list_head q_messages;
 	struct list_head q_receivers;
@@ -329,16 +329,109 @@
 	return ret;
 }
 
+static inline unsigned long copy_msqid_to_user(void *buf, struct msqid64_ds *in, int version)
+{
+	switch(version) {
+	case IPC_64:
+		return copy_to_user (buf, in, sizeof(*in));
+	case IPC_OLD:
+	    {
+		struct msqid_ds out;
+
+		memset(&out,0,sizeof(out));
+
+		ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);
+
+		out.msg_stime		= in->msg_stime;
+		out.msg_rtime		= in->msg_rtime;
+		out.msg_ctime		= in->msg_ctime;
+
+		if(in->msg_cbytes > USHRT_MAX)
+			out.msg_cbytes	= USHRT_MAX;
+		else
+			out.msg_cbytes	= in->msg_cbytes;
+		out.msg_lcbytes		= in->msg_cbytes;
+
+		if(in->msg_qnum > USHRT_MAX)
+			out.msg_qnum	= USHRT_MAX;
+		else
+			out.msg_qnum	= in->msg_qnum;
+
+		if(in->msg_qbytes > USHRT_MAX)
+			out.msg_qbytes	= USHRT_MAX;
+		else
+			out.msg_qbytes	= in->msg_qbytes;
+		out.msg_lqbytes		= in->msg_qbytes;
+
+		out.msg_lspid		= in->msg_lspid;
+		out.msg_lrpid		= in->msg_lrpid;
+
+		return copy_to_user (buf, &out, sizeof(out));
+	    }
+	default:
+		return -EINVAL;
+	}
+}
+
+struct msq_setbuf {
+	unsigned long	qbytes;
+	uid_t		uid;
+	gid_t		gid;
+	mode_t		mode;
+};
+
+static inline unsigned long copy_msqid_from_user(struct msq_setbuf *out, void *buf, int version)
+{
+	switch(version) {
+	case IPC_64:
+	    {
+		struct msqid64_ds tbuf;
+
+		if (copy_from_user (&tbuf, buf, sizeof (tbuf)))
+			return -EFAULT;
+
+		out->qbytes		= tbuf.msg_qbytes;
+		out->uid		= tbuf.msg_perm.uid;
+		out->gid		= tbuf.msg_perm.gid;
+		out->mode		= tbuf.msg_perm.mode;
+
+		return 0;
+	    }
+	case IPC_OLD:
+	    {
+		struct msqid_ds tbuf_old;
+
+		if (copy_from_user (&tbuf_old, buf, sizeof (tbuf_old)))
+			return -EFAULT;
+
+		out->uid		= tbuf_old.msg_perm.uid;
+		out->gid		= tbuf_old.msg_perm.gid;
+		out->mode		= tbuf_old.msg_perm.mode;
+
+		if(tbuf_old.msg_qbytes == 0)
+			out->qbytes	= tbuf_old.msg_lqbytes;
+		else
+			out->qbytes	= tbuf_old.msg_qbytes;
+
+		return 0;
+	    }
+	default:
+		return -EINVAL;
+	}
+}
+
 asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
 {
-	int err;
+	int err, version;
 	struct msg_queue *msq;
-	struct msqid_ds tbuf;
-	struct ipc_perm *ipcp;
+	struct msq_setbuf setbuf;
+	struct kern_ipc_perm *ipcp;
 	
 	if (msqid < 0 || cmd < 0)
 		return -EINVAL;
 
+	version = ipc_parse_version(&cmd);
+
 	switch (cmd) {
 	case IPC_INFO: 
 	case MSG_INFO: 
@@ -376,12 +469,15 @@
 	case MSG_STAT:
 	case IPC_STAT:
 	{
+		struct msqid64_ds tbuf;
 		int success_return;
 		if (!buf)
 			return -EFAULT;
 		if(cmd == MSG_STAT && msqid > msg_ids.size)
 			return -EINVAL;
 
+		memset(&tbuf,0,sizeof(tbuf));
+
 		msq = msg_lock(msqid);
 		if (msq == NULL)
 			return -EINVAL;
@@ -398,40 +494,24 @@
 		if (ipcperms (&msq->q_perm, S_IRUGO))
 			goto out_unlock;
 
-		memset(&tbuf,0,sizeof(tbuf));
-		tbuf.msg_perm   = msq->q_perm;
-		/* tbuf.msg_{first,last}: not reported.*/
+		kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
 		tbuf.msg_stime  = msq->q_stime;
 		tbuf.msg_rtime  = msq->q_rtime;
 		tbuf.msg_ctime  = msq->q_ctime;
-		if(msq->q_cbytes > USHRT_MAX)
-			tbuf.msg_cbytes = USHRT_MAX;
-		 else
-			tbuf.msg_cbytes = msq->q_cbytes;
-		tbuf.msg_lcbytes = msq->q_cbytes;
-		
-		if(msq->q_qnum > USHRT_MAX)
-			tbuf.msg_qnum = USHRT_MAX;
-		 else
-			tbuf.msg_qnum   = msq->q_qnum;
-
-		if(msq->q_qbytes > USHRT_MAX)
-			tbuf.msg_qbytes = USHRT_MAX;
-		 else
-			tbuf.msg_qbytes = msq->q_qbytes;
-		tbuf.msg_lqbytes = msq->q_qbytes;
-
+		tbuf.msg_cbytes = msq->q_cbytes;
+		tbuf.msg_qnum   = msq->q_qnum;
+		tbuf.msg_qbytes = msq->q_qbytes;
 		tbuf.msg_lspid  = msq->q_lspid;
 		tbuf.msg_lrpid  = msq->q_lrpid;
 		msg_unlock(msqid);
-		if (copy_to_user (buf, &tbuf, sizeof(*buf)))
+		if (copy_msqid_to_user(buf, &tbuf, version))
 			return -EFAULT;
 		return success_return;
 	}
 	case IPC_SET:
 		if (!buf)
 			return -EFAULT;
-		if (copy_from_user (&tbuf, buf, sizeof (*buf)))
+		if (copy_msqid_from_user (&setbuf, buf, version))
 			return -EFAULT;
 		break;
 	case IPC_RMID:
@@ -459,19 +539,14 @@
 	switch (cmd) {
 	case IPC_SET:
 	{
-		int newqbytes;
-		if(tbuf.msg_qbytes == 0)
-			newqbytes = tbuf.msg_lqbytes;
-		 else
-		 	newqbytes = tbuf.msg_qbytes;
-		if (newqbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
+		if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
 			goto out_unlock_up;
-		msq->q_qbytes = newqbytes;
+		msq->q_qbytes = setbuf.qbytes;
 
-		ipcp->uid = tbuf.msg_perm.uid;
-		ipcp->gid =  tbuf.msg_perm.gid;
+		ipcp->uid = setbuf.uid;
+		ipcp->gid = setbuf.gid;
 		ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
-			(S_IRWXUGO & tbuf.msg_perm.mode);
+			(S_IRWXUGO & setbuf.mode);
 		msq->q_ctime = CURRENT_TIME;
 		/* sleeping receivers might be excluded by
 		 * stricter permissions.
diff -u --recursive --new-file v2.3.38/linux/ipc/sem.c linux/ipc/sem.c
--- v2.3.38/linux/ipc/sem.c	Tue Dec  7 09:32:51 1999
+++ linux/ipc/sem.c	Mon Jan 10 18:15:58 2000
@@ -64,9 +64,9 @@
 #include "util.h"
 
 
-#define sem_lock(id)	((struct semid_ds*)ipc_lock(&sem_ids,id))
+#define sem_lock(id)	((struct sem_array*)ipc_lock(&sem_ids,id))
 #define sem_unlock(id)	ipc_unlock(&sem_ids,id)
-#define sem_rmid(id)	((struct semid_ds*)ipc_rmid(&sem_ids,id))
+#define sem_rmid(id)	((struct sem_array*)ipc_rmid(&sem_ids,id))
 #define sem_checkid(sma, semid)	\
 	ipc_checkid(&sem_ids,&sma->sem_perm,semid)
 #define sem_buildid(id, seq) \
@@ -85,8 +85,8 @@
 /*
  * linked list protection:
  *	sem_undo.id_next,
- *	semid_ds.sem_pending{,last},
- *	semid_ds.sem_undo: sem_lock() for read/write
+ *	sem_array.sem_pending{,last},
+ *	sem_array.sem_undo: sem_lock() for read/write
  *	sem_undo.proc_next: only "current" is allowed to read/write that field.
  *	
  */
@@ -112,7 +112,7 @@
 static int newary (key_t key, int nsems, int semflg)
 {
 	int id;
-	struct semid_ds *sma;
+	struct sem_array *sma;
 	int size;
 
 	if (!nsems)
@@ -121,7 +121,7 @@
 		return -ENOSPC;
 
 	size = sizeof (*sma) + nsems * sizeof (struct sem);
-	sma = (struct semid_ds *) ipc_alloc(size);
+	sma = (struct sem_array *) ipc_alloc(size);
 	if (!sma) {
 		return -ENOMEM;
 	}
@@ -150,7 +150,7 @@
 asmlinkage long sys_semget (key_t key, int nsems, int semflg)
 {
 	int id, err = -EINVAL;
-	struct semid_ds *sma;
+	struct sem_array *sma;
 
 	if (nsems < 0 || nsems > sc_semmsl)
 		return -EINVAL;
@@ -183,9 +183,9 @@
 }
 
 /* doesn't acquire the sem_lock on error! */
-static int sem_revalidate(int semid, struct semid_ds* sma, int nsems, short flg)
+static int sem_revalidate(int semid, struct sem_array* sma, int nsems, short flg)
 {
-	struct semid_ds* smanew;
+	struct sem_array* smanew;
 
 	smanew = sem_lock(semid);
 	if(smanew==NULL)
@@ -204,14 +204,14 @@
 /* Manage the doubly linked list sma->sem_pending as a FIFO:
  * insert new queue elements at the tail sma->sem_pending_last.
  */
-static inline void append_to_queue (struct semid_ds * sma,
+static inline void append_to_queue (struct sem_array * sma,
 				    struct sem_queue * q)
 {
 	*(q->prev = sma->sem_pending_last) = q;
 	*(sma->sem_pending_last = &q->next) = NULL;
 }
 
-static inline void prepend_to_queue (struct semid_ds * sma,
+static inline void prepend_to_queue (struct sem_array * sma,
 				     struct sem_queue * q)
 {
 	q->next = sma->sem_pending;
@@ -222,7 +222,7 @@
 		sma->sem_pending_last = &q->next;
 }
 
-static inline void remove_from_queue (struct semid_ds * sma,
+static inline void remove_from_queue (struct sem_array * sma,
 				      struct sem_queue * q)
 {
 	*(q->prev) = q->next;
@@ -238,7 +238,7 @@
  * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
  */
 
-static int try_atomic_semop (struct semid_ds * sma, struct sembuf * sops,
+static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
 			     int nsops, struct sem_undo *un, int pid,
 			     int do_undo)
 {
@@ -301,7 +301,7 @@
 /* Go through the pending queue for the indicated semaphore
  * looking for tasks that can be completed.
  */
-static void update_queue (struct semid_ds * sma)
+static void update_queue (struct sem_array * sma)
 {
 	int error;
 	struct sem_queue * q;
@@ -338,7 +338,7 @@
  * The counts we return here are a rough approximation, but still
  * warrant that semncnt+semzcnt>0 if the task is on the pending queue.
  */
-static int count_semncnt (struct semid_ds * sma, ushort semnum)
+static int count_semncnt (struct sem_array * sma, ushort semnum)
 {
 	int semncnt;
 	struct sem_queue * q;
@@ -356,7 +356,7 @@
 	}
 	return semncnt;
 }
-static int count_semzcnt (struct semid_ds * sma, ushort semnum)
+static int count_semzcnt (struct sem_array * sma, ushort semnum)
 {
 	int semzcnt;
 	struct sem_queue * q;
@@ -378,7 +378,7 @@
 /* Free a semaphore set. */
 static void freeary (int id)
 {
-	struct semid_ds *sma;
+	struct sem_array *sma;
 	struct sem_undo *un;
 	struct sem_queue *q;
 	int size;
@@ -405,7 +405,29 @@
 	ipc_free(sma, size);
 }
 
-int semctl_nolock(int semid, int semnum, int cmd, union semun arg)
+static unsigned long copy_semid_to_user(void *buf, struct semid64_ds *in, int version)
+{
+	switch(version) {
+	case IPC_64:
+		return copy_to_user(buf, in, sizeof(*in));
+	case IPC_OLD:
+	    {
+		struct semid_ds out;
+
+		ipc64_perm_to_ipc_perm(&in->sem_perm, &out.sem_perm);
+
+		out.sem_otime	= in->sem_otime;
+		out.sem_ctime	= in->sem_ctime;
+		out.sem_nsems	= in->sem_nsems;
+
+		return copy_to_user(buf, &out, sizeof(out));
+	    }
+	default:
+		return -EINVAL;
+	}
+}
+
+int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
 {
 	int err = -EINVAL;
 
@@ -441,13 +463,15 @@
 	}
 	case SEM_STAT:
 	{
-		struct semid_ds *sma;
-		struct semid_ds tbuf;
+		struct sem_array *sma;
+		struct semid64_ds tbuf;
 		int id;
 
 		if(semid > sem_ids.size)
 			return -EINVAL;
 
+		memset(&tbuf,0,sizeof(tbuf));
+
 		sma = sem_lock(semid);
 		if(sma == NULL)
 			return -EINVAL;
@@ -457,13 +481,12 @@
 			goto out_unlock;
 		id = sem_buildid(semid, sma->sem_perm.seq);
 
-		memset(&tbuf,0,sizeof(tbuf));
-		tbuf.sem_perm   = sma->sem_perm;
+		kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
 		tbuf.sem_otime  = sma->sem_otime;
 		tbuf.sem_ctime  = sma->sem_ctime;
 		tbuf.sem_nsems  = sma->sem_nsems;
 		sem_unlock(semid);
-		if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf)))
+		if (copy_semid_to_user (arg.buf, &tbuf, version))
 			return -EFAULT;
 		return id;
 	}
@@ -476,9 +499,9 @@
 	return err;
 }
 
-int semctl_main(int semid, int semnum, int cmd, union semun arg)
+int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
 {
-	struct semid_ds *sma;
+	struct sem_array *sma;
 	struct sem* curr;
 	int err;
 	ushort fast_sem_io[SEMMSL_FAST];
@@ -564,14 +587,14 @@
 	}
 	case IPC_STAT:
 	{
-		struct semid_ds tbuf;
+		struct semid64_ds tbuf;
 		memset(&tbuf,0,sizeof(tbuf));
-		tbuf.sem_perm   = sma->sem_perm;
+		kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
 		tbuf.sem_otime  = sma->sem_otime;
 		tbuf.sem_ctime  = sma->sem_ctime;
 		tbuf.sem_nsems  = sma->sem_nsems;
 		sem_unlock(semid);
-		if (copy_to_user (arg.buf, &tbuf, sizeof(tbuf)))
+		if (copy_semid_to_user (arg.buf, &tbuf, version))
 			return -EFAULT;
 		return 0;
 	}
@@ -622,15 +645,55 @@
 	return err;
 }
 
-int semctl_down(int semid, int semnum, int cmd, union semun arg)
+struct sem_setbuf {
+	uid_t	uid;
+	gid_t	gid;
+	mode_t	mode;
+};
+
+static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void *buf, int version)
+{
+	switch(version) {
+	case IPC_64:
+	    {
+		struct semid64_ds tbuf;
+
+		if(copy_from_user(&tbuf, buf, sizeof(tbuf)))
+			return -EFAULT;
+
+		out->uid	= tbuf.sem_perm.uid;
+		out->gid	= tbuf.sem_perm.gid;
+		out->mode	= tbuf.sem_perm.mode;
+
+		return 0;
+	    }
+	case IPC_OLD:
+	    {
+		struct semid_ds tbuf_old;
+
+		if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
+			return -EFAULT;
+
+		out->uid	= tbuf_old.sem_perm.uid;
+		out->gid	= tbuf_old.sem_perm.gid;
+		out->mode	= tbuf_old.sem_perm.mode;
+
+		return 0;
+	    }
+	default:
+		return -EINVAL;
+	}
+}
+
+int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
 {
-	struct semid_ds *sma;
+	struct sem_array *sma;
 	int err;
-	struct semid_ds tbuf;
-	struct ipc_perm *ipcp;
+	struct sem_setbuf setbuf;
+	struct kern_ipc_perm *ipcp;
 
 	if(cmd == IPC_SET) {
-		if(copy_from_user (&tbuf, arg.buf, sizeof (tbuf)))
+		if(copy_semid_from_user (&setbuf, arg.buf, version))
 			return -EFAULT;
 	}
 	sma = sem_lock(semid);
@@ -655,10 +718,10 @@
 		err = 0;
 		break;
 	case IPC_SET:
-		ipcp->uid = tbuf.sem_perm.uid;
-		ipcp->gid = tbuf.sem_perm.gid;
+		ipcp->uid = setbuf.uid;
+		ipcp->gid = setbuf.gid;
 		ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
-				| (tbuf.sem_perm.mode & S_IRWXUGO);
+				| (setbuf.mode & S_IRWXUGO);
 		sma->sem_ctime = CURRENT_TIME;
 		sem_unlock(semid);
 		err = 0;
@@ -678,15 +741,18 @@
 asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
 {
 	int err = -EINVAL;
+	int version;
 
 	if (semid < 0)
 		return -EINVAL;
 
+	version = ipc_parse_version(&cmd);
+
 	switch(cmd) {
 	case IPC_INFO:
 	case SEM_INFO:
 	case SEM_STAT:
-		err = semctl_nolock(semid,semnum,cmd,arg);
+		err = semctl_nolock(semid,semnum,cmd,version,arg);
 		return err;
 	case GETALL:
 	case GETVAL:
@@ -696,12 +762,12 @@
 	case IPC_STAT:
 	case SETVAL:
 	case SETALL:
-		err = semctl_main(semid,semnum,cmd,arg);
+		err = semctl_main(semid,semnum,cmd,version,arg);
 		return err;
 	case IPC_RMID:
 	case IPC_SET:
 		down(&sem_ids.sem);
-		err = semctl_down(semid,semnum,cmd,arg);
+		err = semctl_down(semid,semnum,cmd,version,arg);
 		up(&sem_ids.sem);
 		return err;
 	default:
@@ -709,7 +775,7 @@
 	}
 }
 
-static struct sem_undo* freeundos(struct semid_ds *sma, struct sem_undo* un)
+static struct sem_undo* freeundos(struct sem_array *sma, struct sem_undo* un)
 {
 	struct sem_undo* u;
 	struct sem_undo** up;
@@ -727,7 +793,7 @@
 }
 
 /* returns without sem_lock on error! */
-static int alloc_undo(struct semid_ds *sma, struct sem_undo** unp, int semid, int alter)
+static int alloc_undo(struct sem_array *sma, struct sem_undo** unp, int semid, int alter)
 {
 	int size, nsems, error;
 	struct sem_undo *un;
@@ -760,7 +826,7 @@
 asmlinkage long sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
 {
 	int error = -EINVAL;
-	struct semid_ds *sma;
+	struct sem_array *sma;
 	struct sembuf fast_sops[SEMOPM_FAST];
 	struct sembuf* sops = fast_sops, *sop;
 	struct sem_undo *un;
@@ -846,7 +912,7 @@
 	current->semsleeping = &queue;
 
 	for (;;) {
-		struct semid_ds* tmp;
+		struct sem_array* tmp;
 		queue.status = -EINTR;
 		queue.sleeper = current;
 		current->state = TASK_INTERRUPTIBLE;
@@ -913,7 +979,7 @@
 {
 	struct sem_queue *q;
 	struct sem_undo *u, *un = NULL, **up, **unp;
-	struct semid_ds *sma;
+	struct sem_array *sma;
 	int nsems, i;
 
 	/* If the current process was sleeping for a semaphore,
@@ -985,7 +1051,7 @@
 	down(&sem_ids.sem);
 
 	for(i = 0; i <= sem_ids.max_id; i++) {
-		struct semid_ds *sma;
+		struct sem_array *sma;
 		sma = sem_lock(i);
 		if(sma) {
 			len += sprintf(buffer + len, "%10d %10d  %4o %5u %5u %5u %5u %5u %10lu %10lu\n",
diff -u --recursive --new-file v2.3.38/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.38/linux/ipc/shm.c	Fri Jan  7 19:13:23 2000
+++ linux/ipc/shm.c	Mon Jan 10 18:15:58 2000
@@ -29,9 +29,18 @@
 
 #include "util.h"
 
-struct shmid_kernel /* extend struct shmis_ds with private fields */
+struct shmid_kernel /* private to the kernel */
 {	
-	struct shmid_ds		u;
+	struct {
+		struct kern_ipc_perm	shm_perm;
+		size_t			shm_segsz;
+		time_t			shm_atime;
+		time_t			shm_dtime;
+		time_t			shm_ctime;
+		pid_t			shm_cpid;
+		pid_t			shm_lpid;
+		unsigned long		shm_nattch;
+	} u;
 	unsigned long		shm_npages; /* size of segment (pages) */
 	pte_t			**shm_dir;  /* ptr to array of ptrs to frames -> SHMMAX */ 
 	struct vm_area_struct	*attaches;  /* descriptors for attaches */
@@ -89,7 +98,6 @@
 /* some statistics */
 static ulong swap_attempts = 0;
 static ulong swap_successes = 0;
-static ulong used_segs = 0;
 
 void __init shm_init (void)
 {
@@ -303,19 +311,112 @@
 	return;
 }
 
+static inline unsigned long copy_shmid_to_user(void *buf, struct shmid64_ds *in, int version)
+{
+	switch(version) {
+	case IPC_64:
+		return copy_to_user(buf, in, sizeof(*in));
+	case IPC_OLD:
+	    {
+		struct shmid_ds out;
+
+		ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
+		out.shm_segsz	= in->shm_segsz;
+		out.shm_atime	= in->shm_atime;
+		out.shm_dtime	= in->shm_dtime;
+		out.shm_ctime	= in->shm_ctime;
+		out.shm_cpid	= in->shm_cpid;
+		out.shm_lpid	= in->shm_lpid;
+		out.shm_nattch	= in->shm_nattch;
+
+		return copy_to_user(buf, &out, sizeof(out));
+	    }
+	default:
+		return -EINVAL;
+	}
+}
+
+struct shm_setbuf {
+	uid_t	uid;
+	gid_t	gid;
+	mode_t	mode;
+};	
+
+static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void *buf, int version)
+{
+	switch(version) {
+	case IPC_64:
+	    {
+		struct shmid64_ds tbuf;
+
+		if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
+			return -EFAULT;
+
+		out->uid	= tbuf.shm_perm.uid;
+		out->gid	= tbuf.shm_perm.gid;
+		out->mode	= tbuf.shm_perm.mode;
+
+		return 0;
+	    }
+	case IPC_OLD:
+	    {
+		struct shmid_ds tbuf_old;
+
+		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
+			return -EFAULT;
+
+		out->uid	= tbuf_old.shm_perm.uid;
+		out->gid	= tbuf_old.shm_perm.gid;
+		out->mode	= tbuf_old.shm_perm.mode;
+
+		return 0;
+	    }
+	default:
+		return -EINVAL;
+	}
+}
+
+static inline unsigned long copy_shminfo_to_user(void *buf, struct shminfo64 *in, int version)
+{
+	switch(version) {
+	case IPC_64:
+		return copy_to_user(buf, in, sizeof(*in));
+	case IPC_OLD:
+	    {
+		struct shminfo out;
+
+		if(in->shmmax > INT_MAX)
+			out.shmmax = INT_MAX;
+		else
+			out.shmmax = (int)in->shmmax;
+
+		out.shmmin	= in->shmmin;
+		out.shmmni	= in->shmmni;
+		out.shmseg	= in->shmseg;
+		out.shmall	= in->shmall; 
+
+		return copy_to_user(buf, &out, sizeof(out));
+	    }
+	default:
+		return -EINVAL;
+	}
+}
+
 asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
 {
-	struct shmid_ds tbuf;
+	struct shm_setbuf setbuf;
 	struct shmid_kernel *shp;
-	int err;
+	int err, version;
 
 	if (cmd < 0 || shmid < 0)
 		return -EINVAL;
 
+	version = ipc_parse_version(&cmd);
+
 	switch (cmd) { /* replace with proc interface ? */
 	case IPC_INFO:
 	{
-		struct shminfo shminfo;
+		struct shminfo64 shminfo;
 
 		memset(&shminfo,0,sizeof(shminfo));
 		shminfo.shmmni = shminfo.shmseg = shm_ctlmni;
@@ -323,7 +424,7 @@
 		shminfo.shmall = shm_ctlall;
 
 		shminfo.shmmin = SHMMIN;
-		if(copy_to_user (buf, &shminfo, sizeof(struct shminfo)))
+		if(copy_shminfo_to_user (buf, &shminfo, version))
 			return -EFAULT;
 		/* reading a integer is always atomic */
 		err= shm_ids.max_id;
@@ -337,7 +438,7 @@
 
 		memset(&shm_info,0,sizeof(shm_info));
 		shm_lockall();
-		shm_info.used_ids = used_segs;
+		shm_info.used_ids = shm_ids.in_use;
 		shm_info.shm_rss = shm_rss;
 		shm_info.shm_tot = shm_tot;
 		shm_info.shm_swp = shm_swp;
@@ -353,8 +454,9 @@
 	case SHM_STAT:
 	case IPC_STAT:
 	{
-		struct shmid_ds tmp;
+		struct shmid64_ds tbuf;
 		int result;
+		memset(&tbuf, 0, sizeof(tbuf));
 		shp = shm_lock(shmid);
 		if(shp==NULL)
 			return -EINVAL;
@@ -372,9 +474,16 @@
 		err=-EACCES;
 		if (ipcperms (&shp->u.shm_perm, S_IRUGO))
 			goto out_unlock;
-		memcpy(&tmp,&shp->u,sizeof(tmp));
+		kernel_to_ipc64_perm(&shp->u.shm_perm, &tbuf.shm_perm);
+		tbuf.shm_segsz	= shp->u.shm_segsz;
+		tbuf.shm_atime	= shp->u.shm_atime;
+		tbuf.shm_dtime	= shp->u.shm_dtime;
+		tbuf.shm_ctime	= shp->u.shm_ctime;
+		tbuf.shm_cpid	= shp->u.shm_cpid;
+		tbuf.shm_lpid	= shp->u.shm_lpid;
+		tbuf.shm_nattch	= shp->u.shm_nattch;
 		shm_unlock(shmid);
-		if(copy_to_user (buf, &tmp, sizeof(tmp)))
+		if(copy_shmid_to_user (buf, &tbuf, version))
 			return -EFAULT;
 		return result;
 	}
@@ -384,7 +493,7 @@
 /* Allow superuser to lock segment in memory */
 /* Should the pages be faulted in here or leave it to user? */
 /* need to determine interaction with current->swappable */
-		struct ipc_perm *ipcp;
+		struct kern_ipc_perm *ipcp;
 		if (!capable(CAP_IPC_LOCK))
 			return -EPERM;
 
@@ -417,7 +526,7 @@
 	}
 
 	if (cmd == IPC_SET) {
-		if(copy_from_user (&tbuf, buf, sizeof (*buf)))
+		if(copy_shmid_from_user (&setbuf, buf, version))
 			return -EFAULT;
 	}
 	down(&shm_ids.sem);
@@ -437,10 +546,10 @@
 
 	switch (cmd) {
 	case IPC_SET:
-		shp->u.shm_perm.uid = tbuf.shm_perm.uid;
-		shp->u.shm_perm.gid = tbuf.shm_perm.gid;
+		shp->u.shm_perm.uid = setbuf.uid;
+		shp->u.shm_perm.gid = setbuf.gid;
 		shp->u.shm_perm.mode = (shp->u.shm_perm.mode & ~S_IRWXUGO)
-			| (tbuf.shm_perm.mode & S_IRWXUGO);
+			| (setbuf.mode & S_IRWXUGO);
 		shp->u.shm_ctime = CURRENT_TIME;
 		break;
 	case IPC_RMID:
diff -u --recursive --new-file v2.3.38/linux/ipc/util.c linux/ipc/util.c
--- v2.3.38/linux/ipc/util.c	Fri Jan  7 19:13:23 2000
+++ linux/ipc/util.c	Mon Jan 10 18:15:58 2000
@@ -18,6 +18,7 @@
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/malloc.h>
+#include <linux/highuid.h>
 
 #if defined(CONFIG_SYSVIPC)
 
@@ -67,7 +68,7 @@
 int ipc_findkey(struct ipc_ids* ids, key_t key)
 {
 	int id;
-	struct ipc_perm* p;
+	struct kern_ipc_perm* p;
 
 	for (id = 0; id <= ids->max_id; id++) {
 		p = ids->entries[id].p;
@@ -108,7 +109,7 @@
 	return ids->size;
 }
 
-int ipc_addid(struct ipc_ids* ids, struct ipc_perm* new, int size)
+int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 {
 	int id;
 
@@ -135,9 +136,9 @@
 	return id;
 }
 
-struct ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
+struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id)
 {
-	struct ipc_perm* p;
+	struct kern_ipc_perm* p;
 	int lid = id % SEQ_MULTIPLIER;
 	if(lid > ids->size)
 		BUG();
@@ -186,7 +187,7 @@
  * Check user, group, other permissions for access
  * to ipc resources. return 0 if allowed
  */
-int ipcperms (struct ipc_perm *ipcp, short flag)
+int ipcperms (struct kern_ipc_perm *ipcp, short flag)
 {	/* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
 	int requested_mode, granted_mode;
 
@@ -202,6 +203,43 @@
 		return -1;
 
 	return 0;
+}
+
+/*
+ * Functions to convert between the kern_ipc_perm structure and the
+ * old/new ipc_perm structures
+ */
+
+void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
+{
+	out->key	= in->key;
+	out->uid	= in->uid;
+	out->gid	= in->gid;
+	out->cuid	= in->cuid;
+	out->cgid	= in->cgid;
+	out->mode	= in->mode;
+	out->seq	= in->seq;
+}
+
+void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
+{
+	out->key	= in->key;
+	out->uid	= NEW_TO_OLD_UID(in->uid);
+	out->gid	= NEW_TO_OLD_GID(in->gid);
+	out->cuid	= NEW_TO_OLD_UID(in->cuid);
+	out->cgid	= NEW_TO_OLD_GID(in->cgid);
+	out->mode	= in->mode;
+	out->seq	= in->seq;
+}
+
+int ipc_parse_version (int *cmd)
+{
+	if (*cmd & IPC_64) {
+		*cmd ^= IPC_64;
+		return IPC_64;
+	} else {
+		return IPC_OLD;
+	}
 }
 
 #else
diff -u --recursive --new-file v2.3.38/linux/ipc/util.h linux/ipc/util.h
--- v2.3.38/linux/ipc/util.h	Tue Dec  7 09:32:51 1999
+++ linux/ipc/util.h	Mon Jan 10 18:15:58 2000
@@ -24,7 +24,7 @@
 };
 
 struct ipc_id {
-	struct ipc_perm* p;
+	struct kern_ipc_perm* p;
 };
 
 
@@ -32,12 +32,12 @@
 
 /* must be called with ids->sem acquired.*/
 int ipc_findkey(struct ipc_ids* ids, key_t key);
-int ipc_addid(struct ipc_ids* ids, struct ipc_perm* new, int size);
+int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
 
 /* must be called with both locks acquired. */
-struct ipc_perm* ipc_rmid(struct ipc_ids* ids, int id);
+struct kern_ipc_perm* ipc_rmid(struct ipc_ids* ids, int id);
 
-int ipcperms (struct ipc_perm *ipcp, short flg);
+int ipcperms (struct kern_ipc_perm *ipcp, short flg);
 
 /* for rare, potentially huge allocations.
  * both function can sleep
@@ -50,9 +50,9 @@
 	spin_lock(&ids->ary);
 }
 
-extern inline struct ipc_perm* ipc_get(struct ipc_ids* ids, int id)
+extern inline struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id)
 {
-	struct ipc_perm* out;
+	struct kern_ipc_perm* out;
 	int lid = id % SEQ_MULTIPLIER;
 	if(lid > ids->size)
 		return NULL;
@@ -65,9 +65,9 @@
 {
 	spin_unlock(&ids->ary);
 }
-extern inline struct ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
+extern inline struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id)
 {
-	struct ipc_perm* out;
+	struct kern_ipc_perm* out;
 	int lid = id % SEQ_MULTIPLIER;
 	if(lid > ids->size)
 		return NULL;
@@ -89,10 +89,13 @@
 	return SEQ_MULTIPLIER*seq + id;
 }
 
-extern inline int ipc_checkid(struct ipc_ids* ids, struct ipc_perm* ipcp, int uid)
+extern inline int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid)
 {
 	if(uid/SEQ_MULTIPLIER != ipcp->seq)
 		return 1;
 	return 0;
 }
 
+void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
+void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
+int ipc_parse_version (int *cmd);
diff -u --recursive --new-file v2.3.38/linux/kernel/Makefile linux/kernel/Makefile
--- v2.3.38/linux/kernel/Makefile	Mon Dec 20 18:48:22 1999
+++ linux/kernel/Makefile	Mon Jan 10 18:15:58 2000
@@ -13,7 +13,7 @@
 O_TARGET := kernel.o
 O_OBJS    = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
-	    sysctl.o acct.o capability.o ptrace.o timer.o
+	    sysctl.o acct.o capability.o ptrace.o timer.o uid16.o
 
 OX_OBJS  += signal.o
 
diff -u --recursive --new-file v2.3.38/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.38/linux/kernel/ksyms.c	Fri Jan  7 19:13:23 2000
+++ linux/kernel/ksyms.c	Sat Jan  8 17:41:17 2000
@@ -247,7 +247,6 @@
 /* block device driver support */
 EXPORT_SYMBOL(block_read);
 EXPORT_SYMBOL(block_write);
-EXPORT_SYMBOL(block_fsync);
 EXPORT_SYMBOL(wait_for_request);
 EXPORT_SYMBOL(blksize_size);
 EXPORT_SYMBOL(hardsect_size);
diff -u --recursive --new-file v2.3.38/linux/kernel/signal.c linux/kernel/signal.c
--- v2.3.38/linux/kernel/signal.c	Mon Oct 11 15:38:15 1999
+++ linux/kernel/signal.c	Mon Jan 10 18:15:58 2000
@@ -12,6 +12,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/highuid.h>
 
 #include <asm/uaccess.h>
 
@@ -143,6 +144,7 @@
 			info->si_code = 0;
 			info->si_pid = 0;
 			info->si_uid = 0;
+			SET_UID16(info->si_uid16, 0);
 		} else {
 			struct signal_queue *q, **pp;
 			pp = &current->sigqueue;
@@ -178,6 +180,7 @@
 				info->si_code = 0;
 				info->si_pid = 0;
 				info->si_uid = 0;
+				SET_UID16(info->si_uid16, 0);
 			}
 		}
 
@@ -340,6 +343,7 @@
 				q->info.si_code = SI_USER;
 				q->info.si_pid = current->pid;
 				q->info.si_uid = current->uid;
+				SET_UID16(q->info.si_uid16, current->uid);
 				break;
 			case 1:
 				q->info.si_signo = sig;
@@ -347,6 +351,7 @@
 				q->info.si_code = SI_KERNEL;
 				q->info.si_pid = 0;
 				q->info.si_uid = 0;
+				SET_UID16(q->info.si_uid16, 0);
 				break;
 			default:
 				q->info = *info;
@@ -729,11 +734,12 @@
 
 	if (copy_from_user(&these, uthese, sizeof(these)))
 		return -EFAULT;
-	else {
-		/* Invert the set of allowed signals to get those we
-		   want to block.  */
-		signotset(&these);
-	}
+		
+	/*
+	 * Invert the set of allowed signals to get those we
+	 * want to block.
+	 */
+	signotset(&these);
 
 	if (uts) {
 		if (copy_from_user(&ts, uts, sizeof(ts)))
@@ -795,6 +801,7 @@
 	info.si_code = SI_USER;
 	info.si_pid = current->pid;
 	info.si_uid = current->uid;
+	SET_UID16(info.si_uid16, current->uid);
 
 	return kill_something_info(sig, &info, pid);
 }
diff -u --recursive --new-file v2.3.38/linux/kernel/sys.c linux/kernel/sys.c
--- v2.3.38/linux/kernel/sys.c	Mon Nov  1 13:56:27 1999
+++ linux/kernel/sys.c	Mon Jan 10 18:15:58 2000
@@ -12,9 +12,26 @@
 #include <linux/reboot.h>
 #include <linux/prctl.h>
 #include <linux/init.h>
+#include <linux/highuid.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
+
+/*
+ * this is where the system-wide overflow UID and GID are defined, for
+ * architectures that now have 32-bit UID/GID but didn't in the past
+ */
+
+int overflowuid = DEFAULT_OVERFLOWUID;
+int overflowgid = DEFAULT_OVERFLOWGID;
+
+/*
+ * the same as above, but for filesystems which can only store a 16-bit
+ * UID and GID. as such, this is needed on all architectures
+ */
+
+int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;
+int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;
 
 /*
  * this indicates whether you can reboot with ctrl-alt-del: the default is yes
diff -u --recursive --new-file v2.3.38/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.3.38/linux/kernel/sysctl.c	Wed Dec 29 13:13:21 1999
+++ linux/kernel/sysctl.c	Mon Jan 10 18:15:58 2000
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sysrq.h>
+#include <linux/highuid.h>
 
 #include <asm/uaccess.h>
 
@@ -42,6 +43,10 @@
 extern int max_threads;
 extern int nr_queued_signals, max_queued_signals;
 
+/* this is needed for the proc_dointvec_minmax for overflow UID and GID */
+static int maxolduid = 65535;
+static int minolduid = 0;
+
 #ifdef CONFIG_KMOD
 extern char modprobe_path[];
 #endif
@@ -242,6 +247,12 @@
 	{KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_RANDOM, "random", NULL, 0, 0555, random_table},
+	{KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL,
+	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
+	 &minolduid, &maxolduid},
+	{KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL,
+	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
+	 &minolduid, &maxolduid},
 	{0}
 };
 
@@ -289,6 +300,12 @@
 	 0644, NULL, &proc_dointvec},
 	{FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
 	 0444, NULL, &proc_dointvec},
+	{FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
+	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
+	 &minolduid, &maxolduid},
+	{FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL,
+	 &proc_dointvec_minmax, &sysctl_intvec, NULL,
+	 &minolduid, &maxolduid},
 	{0}
 };
 
diff -u --recursive --new-file v2.3.38/linux/kernel/uid16.c linux/kernel/uid16.c
--- v2.3.38/linux/kernel/uid16.c	Wed Dec 31 16:00:00 1969
+++ linux/kernel/uid16.c	Mon Jan 10 18:40:26 2000
@@ -0,0 +1,163 @@
+/*
+ *	Wrapper functions for 16bit uid back compatibility. All nicely tied
+ *	together in the faint hope we can take the out in five years time.
+ */
+
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/mman.h>
+#include <linux/smp_lock.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/prctl.h>
+#include <linux/init.h>
+#include <linux/highuid.h>
+
+#include <asm/uaccess.h>
+
+extern asmlinkage long sys_chown(const char *, uid_t,gid_t);
+extern asmlinkage long sys_lchown(const char *, uid_t,gid_t);
+extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t);
+extern asmlinkage long sys_setregid(gid_t, gid_t);
+extern asmlinkage long sys_setgid(gid_t);
+extern asmlinkage long sys_setreuid(uid_t, uid_t);
+extern asmlinkage long sys_setuid(uid_t);
+extern asmlinkage long sys_setresuid(uid_t, uid_t, uid_t);
+extern asmlinkage long sys_setresgid(gid_t, gid_t, gid_t);
+extern asmlinkage long sys_setfsuid(uid_t);
+extern asmlinkage long sys_setfsgid(gid_t);
+ 
+asmlinkage long sys_chown16(const char * filename, old_uid_t user, old_gid_t group)
+{
+	return sys_chown(filename, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys_lchown16(const char * filename, old_uid_t user, old_gid_t group)
+{
+	return sys_lchown(filename, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group)
+{
+	return sys_fchown(fd, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid)
+{
+	return sys_setregid(low2highgid(rgid), low2highgid(egid));
+}
+
+asmlinkage long sys_setgid16(old_gid_t gid)
+{
+	return sys_setgid((gid_t)gid);
+}
+
+asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid)
+{
+	return sys_setreuid(low2highuid(ruid), low2highuid(euid));
+}
+
+asmlinkage long sys_setuid16(old_uid_t uid)
+{
+	return sys_setuid((uid_t)uid);
+}
+
+asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
+{
+	return sys_setresuid(low2highuid(ruid), low2highuid(euid),
+		low2highuid(suid));
+}
+
+asmlinkage long sys_getresuid16(old_uid_t *ruid, old_uid_t *euid, old_uid_t *suid)
+{
+	int retval;
+
+	if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
+	    !(retval = put_user(high2lowuid(current->euid), euid)))
+		retval = put_user(high2lowuid(current->suid), suid);
+
+	return retval;
+}
+
+asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid)
+{
+	return sys_setresgid(low2highgid(rgid), low2highgid(egid),
+		low2highgid(sgid));
+}
+
+asmlinkage long sys_getresgid16(old_gid_t *rgid, old_gid_t *egid, old_gid_t *sgid)
+{
+	int retval;
+
+	if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
+	    !(retval = put_user(high2lowgid(current->egid), egid)))
+		retval = put_user(high2lowgid(current->sgid), sgid);
+
+	return retval;
+}
+
+asmlinkage long sys_setfsuid16(old_uid_t uid)
+{
+	return sys_setfsuid((uid_t)uid);
+}
+
+asmlinkage long sys_setfsgid16(old_gid_t gid)
+{
+	return sys_setfsgid((gid_t)gid);
+}
+
+asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t *grouplist)
+{
+	old_gid_t groups[NGROUPS];
+	int i,j;
+
+	if (gidsetsize < 0)
+		return -EINVAL;
+	i = current->ngroups;
+	if (gidsetsize) {
+		if (i > gidsetsize)
+			return -EINVAL;
+		for(j=0;j<i;j++)
+			groups[j] = current->groups[j];
+		if (copy_to_user(grouplist, groups, sizeof(old_gid_t)*i))
+			return -EFAULT;
+	}
+	return i;
+}
+
+asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t *grouplist)
+{
+	old_gid_t groups[NGROUPS];
+	int i;
+
+	if (!capable(CAP_SETGID))
+		return -EPERM;
+	if ((unsigned) gidsetsize > NGROUPS)
+		return -EINVAL;
+	if (copy_from_user(groups, grouplist, gidsetsize * sizeof(old_gid_t)))
+		return -EFAULT;
+	for (i = 0 ; i < gidsetsize ; i++)
+		current->groups[i] = (gid_t)groups[i];
+	current->ngroups = gidsetsize;
+	return 0;
+}
+
+asmlinkage long sys_getuid16(void)
+{
+	return high2lowuid(current->uid);
+}
+
+asmlinkage long sys_geteuid16(void)
+{
+	return high2lowuid(current->euid);
+}
+
+asmlinkage long sys_getgid16(void)
+{
+	return high2lowgid(current->gid);
+}
+
+asmlinkage long sys_getegid16(void)
+{
+	return high2lowgid(current->egid);
+}
diff -u --recursive --new-file v2.3.38/linux/lib/string.c linux/lib/string.c
--- v2.3.38/linux/lib/string.c	Fri Jan  7 19:13:23 2000
+++ linux/lib/string.c	Sat Jan  8 12:54:54 2000
@@ -369,7 +369,7 @@
 	const unsigned char *p = s;
 	while (n-- != 0) {
         	if ((unsigned char)c == *p++) {
-			return (void *)p-1;
+			return (void *)(p-1);
 		}
 	}
 	return NULL;
diff -u --recursive --new-file v2.3.38/linux/mm/memory.c linux/mm/memory.c
--- v2.3.38/linux/mm/memory.c	Tue Jan  4 13:57:21 2000
+++ linux/mm/memory.c	Mon Jan 10 14:05:33 2000
@@ -560,8 +560,8 @@
 		map = iobuf->maplist[i];
 		
 		if (map && iobuf->locked) {
-			__free_page(map);
 			UnlockPage(map);
+			__free_page(map);
 		}
 	}
 	
diff -u --recursive --new-file v2.3.38/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.3.38/linux/net/core/iovec.c	Tue Sep  7 12:14:07 1999
+++ linux/net/core/iovec.c	Sat Jan  8 21:36:20 2000
@@ -99,7 +99,41 @@
 	}
 	err = 0;
 out:
-	return err; 
+	return err;
+}
+
+/* Copy and checkum skb to user iovec. Caller _must_ check that
+   skb will fit to this iovec.
+ */
+
+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 mecpy_toiove, 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 csum_error;
+	} 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 -EFAULT;
 }
 
 /*
diff -u --recursive --new-file v2.3.38/linux/net/decnet/Config.in linux/net/decnet/Config.in
--- v2.3.38/linux/net/decnet/Config.in	Wed Oct 27 16:34:12 1999
+++ linux/net/decnet/Config.in	Sat Jan  8 21:36:20 2000
@@ -4,5 +4,8 @@
 bool '  DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    bool '  DECnet: router support (EXPERIMENTAL)' CONFIG_DECNET_ROUTER
+   if [ "$CONFIG_DECNET_ROUTER"  = "y" ]; then
+      bool '    DECnet: use FWMARK value as routing key' CONFIG_DECNET_ROUTE_FWMARK
+   fi
 fi
 bool '  DECnet: raw socket support' CONFIG_DECNET_RAW
diff -u --recursive --new-file v2.3.38/linux/net/decnet/Makefile linux/net/decnet/Makefile
--- v2.3.38/linux/net/decnet/Makefile	Tue Dec 14 01:27:24 1999
+++ linux/net/decnet/Makefile	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
 M_OBJS	 := $(O_TARGET)
 
 ifeq ($(CONFIG_DECNET_ROUTER),y)
-O_OBJS += dn_fib.o
+O_OBJS += dn_fib.o dn_rules.o dn_table.o
 endif
 
 ifeq ($(CONFIG_DECNET_RAW),y)
diff -u --recursive --new-file v2.3.38/linux/net/decnet/TODO linux/net/decnet/TODO
--- v2.3.38/linux/net/decnet/TODO	Thu Aug 26 13:05:45 1999
+++ linux/net/decnet/TODO	Sat Jan  8 21:36:20 2000
@@ -4,8 +4,6 @@
  o Proper timeouts on each neighbour (in routing mode) rather than
    just the 60 second On-Ethernet cache value.
 
- o Routing stuff in dn_fib.c
-
  o Misc. get/set_sockopt() functions [done for the time being, more later]
 
  o Support for X.25 linklayer
@@ -16,9 +14,11 @@
 
  o PPP support (rfc1762)
 
- o sendmsg() in the raw socket layer
+ o sendmsg() in the raw socket layer (yes, its for sending routing messages)
 
- o Better filtering of traffic in raw sockets
+ o Better filtering of traffic in raw sockets. Aside from receiving routing
+   messages, there really doesn't seem to be a lot else that raw sockets
+   could be useful for... suggestions on a postcard please :-)
 
  o Fix /proc for raw sockets
 
@@ -33,19 +33,31 @@
 
  o check MSG_TRUNC, MSG_CTRUNC are set where they should be.
 
- o Work out if I really need support for rtnetlink "link" messages and if
-   so how they should be handled.
-
- o More rtnetlink "route" message support & testing of this code
-
- o Routing ioctl() support
-
  o Start to hack together user level software and add more DECnet support
    in ifconfig for example. 
 
- o Fix conninit_rx to check out each CI before queuing it
+ o Fix conninit_rx to check out each CI before queuing it. Support code is
+   now in place, so this should be easy.
 
- o Work out which errors we can return from conninit_rx, and how to do it
+ o Work out which errors we can return from conninit_rx. Support code is
+   now in place, so this should be easy.
 
  o Check out receiving of errors in the light of what conninit_rx can return
+
+ o Test adding/deleting of routes
+
+ o Test route lookup
+
+ o Test /proc/net/decnet_route route listing works correctly (maybe I'll
+   change the format of this file... atm its very similar to the IPv4 route
+   file)
+
+ o Find all the commonality between DECnet and IPv4 routing code and extract 
+   it into a small library of routines. [probably a project for 2.5.xx]
+
+ o Test ip_gre tunneling works... it did the last time I tested it and it
+   will have to if I'm to test routing properly.
+
+ o Hello messages should be generated for each primary address on each
+   interface.
 
diff -u --recursive --new-file v2.3.38/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.3.38/linux/net/decnet/af_decnet.c	Tue Nov 23 22:42:21 1999
+++ linux/net/decnet/af_decnet.c	Sat Jan  8 21:36:20 2000
@@ -135,7 +135,6 @@
  */
 dn_address decnet_address = 0;
 unsigned char decnet_ether_address[ETH_ALEN] = { 0xAA, 0x00, 0x04, 0x00, 0x00, 0x00 };
-int decnet_node_type = DN_RT_INFO_ENDN;
 
 static struct proto_ops dn_proto_ops;
 rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
@@ -484,10 +483,9 @@
  * When socket is dead & no packets have been sent for a
  * certain amount of time, they are removed by this
  * routine. Also takes care of sending out DI & DC
- * frames at correct times. This is called by both
- * socket level and interrupt driven code.
+ * frames at correct times.
  */
-static int dn_destroy_timer(struct sock *sk)
+int dn_destroy_timer(struct sock *sk)
 {
 	struct dn_scp *scp = &sk->protinfo.dn;
 
@@ -495,13 +493,13 @@
 
 	switch(scp->state) {
 		case DN_DI:
-			dn_send_disc(sk, NSP_DISCINIT, 0);
+			dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
 			if (scp->nsp_rxtshift >= decnet_di_count)
 				scp->state = DN_CN;
 			return 0;
 
 		case DN_DR:
-			dn_send_disc(sk, NSP_DISCINIT, 0);
+			dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_ATOMIC);
 			if (scp->nsp_rxtshift >= decnet_dr_count)
 				scp->state = DN_DRC;
 			return 0;
@@ -509,7 +507,7 @@
 		case DN_DN:
 			if (scp->nsp_rxtshift < decnet_dn_count) {
 				/* printk(KERN_DEBUG "dn_destroy_timer: DN\n"); */
-				dn_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC);
+				dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
 				return 0;
 			}
 	}
@@ -529,7 +527,7 @@
 	return 0;
 }
 
-void dn_destroy_sock(struct sock *sk)
+static void dn_destroy_sock(struct sock *sk)
 {
 	struct dn_scp *scp = &sk->protinfo.dn;
 
@@ -548,11 +546,10 @@
 
 	switch(scp->state) {
 		case DN_DN:
-			dn_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC);
+			dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_KERNEL);
 			scp->persist_fxn = dn_destroy_timer;
 			scp->persist = dn_nsp_persist(sk);
 			break;
-		case DN_CD:
 		case DN_CR:
 			scp->state = DN_DR;
 			goto disc_reject;
@@ -561,7 +558,7 @@
 		case DN_DI:
 		case DN_DR:
 disc_reject:
-			dn_send_disc(sk, NSP_DISCINIT, 0);
+			dn_nsp_send_disc(sk, NSP_DISCINIT, 0, GFP_KERNEL);
 		case DN_NC:
 		case DN_NR:
 		case DN_RJ:
@@ -569,6 +566,7 @@
 		case DN_CN:
 		case DN_DRC:
 		case DN_CI:
+		case DN_CD:
 			scp->persist_fxn = dn_destroy_timer;
 			scp->persist = dn_nsp_persist(sk);
 			break;
@@ -1041,7 +1039,7 @@
 
 	if (newsk->protinfo.dn.accept_mode == ACC_IMMED) {
 		newsk->protinfo.dn.state = DN_CC;
-        	dn_send_conn_conf(newsk);
+        	dn_send_conn_conf(newsk, GFP_KERNEL);
 		err = dn_wait_accept(newsock, flags);
 	}
 
@@ -1392,7 +1390,7 @@
 				return -EINVAL;
 
 			scp->state = DN_CC;
-			dn_send_conn_conf(sk);
+			dn_send_conn_conf(sk, GFP_KERNEL);
 			err = dn_wait_accept(sock, sock->file->f_flags);
 			return err;
 
@@ -1403,7 +1401,7 @@
 
 			scp->state = DN_DR;
 			sk->shutdown = SHUTDOWN_MASK;
-			dn_send_disc(sk, 0x38, 0);
+			dn_nsp_send_disc(sk, 0x38, 0, GFP_KERNEL);
 			break;
 
 #ifdef CONFIG_DECNET_FW
@@ -1426,7 +1424,7 @@
                         if (copy_from_user(&tmp_fw, optval, optlen))
                                 return -EFAULT;
                         err = dn_fw_ctl(optname, &tmp_fw, optlen);
-                        return -err;    /* -0 is 0 after all */
+                        return err;
 #endif
 		default:
 		case DSO_LINKINFO:
@@ -1540,7 +1538,7 @@
 
 		case DN_CR:
 			scp->state = DN_CC;
-			dn_send_conn_conf(sk);
+			dn_send_conn_conf(sk, GFP_KERNEL);
 			return dn_wait_accept(sk->socket, (flags & MSG_DONTWAIT) ? O_NONBLOCK : 0);
 		case DN_CI:
 		case DN_CC:
@@ -2072,6 +2070,8 @@
 
 void __init decnet_proto_init(struct net_proto *pro)
 {
+        printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.38s (C) 1995-1999 Linux DECnet Project Team\n");
+
 	sock_register(&dn_family_ops);
 	dev_add_pack(&dn_dix_packet_type);
 	register_netdevice_notifier(&dn_dev_notifier);
@@ -2084,10 +2084,6 @@
 	dn_neigh_init();
 	dn_route_init();
 
-#ifdef CONFIG_DECNET_FW
-	dn_fw_init();
-#endif /* CONFIG_DECNET_FW */
-
 #ifdef CONFIG_DECNET_ROUTER
 	dn_fib_init();
 #endif /* CONFIG_DECNET_ROUTER */
@@ -2095,7 +2091,6 @@
 #ifdef CONFIG_SYSCTL
 	dn_register_sysctl();
 #endif /* CONFIG_SYSCTL */
-        printk(KERN_INFO "NET4: DECnet for Linux: V.2.3.15s (C) 1995-1999 Linux DECnet Project Team\n");
 
 }
 
@@ -2104,27 +2099,11 @@
 {
 	unsigned short area = simple_strtoul(str, &str, 0);
 	unsigned short node = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
-	unsigned short type = simple_strtoul(*str > 0 ? ++str : str, &str, 0);
+	/* unsigned short type = simple_strtoul(*str > 0 ? ++str : str, &str, 0); */
 
 	decnet_address = dn_htons(area << 10 | node);
 	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 
-	switch(type) {
-		default:
-			printk(KERN_INFO "Invalid DECnet node type, switching to EndNode\n");
-		case 0:
-			decnet_node_type = DN_RT_INFO_ENDN;
-			break;
-#ifdef CONFIG_DECNET_ROUTER
-		case 1:
-			decnet_node_type = DN_RT_INFO_L1RT;
-			break;
-		case 2:
-			decnet_node_type = DN_RT_INFO_L2RT;
-			break;
-#endif /* CONFIG_DECNET_ROUTER */
-	}
-
 	return 0;
 }
 
@@ -2137,18 +2116,11 @@
 MODULE_AUTHOR("Linux DECnet Project Team");
 
 static int addr[2] = {0, 0};
-#ifdef CONFIG_DECNET_ROUTER
-static int type = 0;
-#endif
 
 MODULE_PARM(addr, "2i");
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
-#ifdef CONFIG_DECNET_ROUTER
-MODULE_PARM(type, "i");
-MODULE_PARM_DESC(type, "The type of this DECnet node: 0=EndNode, 1,2=Router");
-#endif
 
-int init_module(void)
+int __init init_module(void)
 {
 	if (addr[0] > 63 || addr[0] < 0) {
 		printk(KERN_ERR "DECnet: Area must be between 0 and 63");
@@ -2163,31 +2135,12 @@
 	decnet_address = dn_htons((addr[0] << 10) | addr[1]);
 	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 
-#ifdef CONFIG_DECNET_ROUTER
-	switch(type) {
-		case 0:
-			decnet_node_type = DN_RT_INFO_ENDN;
-			break;
-		case 1:
-			decnet_node_type = DN_RT_INFO_L1RT;
-			break;
-		case 2:
-			decnet_node_type = DN_RT_INFO_L2RT;
-			break;
-		default:
-			printk(KERN_ERR "DECnet: Node type must be between 0 and 2 inclusive\n");
-			return 1;
-	}
-#else
-	decnet_node_type = DN_RT_INFO_ENDN;
-#endif
-
 	decnet_proto_init(NULL);
 
 	return 0;
 }
 
-void cleanup_module(void)
+void __exit cleanup_module(void)
 {
 #ifdef CONFIG_SYSCTL
 	dn_unregister_sysctl();
@@ -2198,10 +2151,6 @@
 	dn_route_cleanup();
 	dn_neigh_cleanup();
 	dn_dev_cleanup();
-
-#ifdef CONFIG_DECNET_FW
-	/* dn_fw_cleanup(); */
-#endif /* CONFIG_DECNET_FW */
 
 #ifdef CONFIG_DECNET_ROUTER
 	dn_fib_cleanup();
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_dev.c linux/net/decnet/dn_dev.c
--- v2.3.38/linux/net/decnet/dn_dev.c	Tue Dec 14 01:27:24 1999
+++ linux/net/decnet/dn_dev.c	Sat Jan  8 21:36:20 2000
@@ -17,6 +17,8 @@
  *          Steve Whitehouse : Fixed bug which sometimes killed timer
  *          Steve Whitehouse : Multiple ifaddr support
  *          Steve Whitehouse : SIOCGIFCONF is now a compile time option
+ *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
+ *          Steve Whitehouse : Removed timer1 - its a user space issue now
  */
 
 #include <linux/config.h>
@@ -59,16 +61,17 @@
 
 static int dn_eth_up(struct net_device *);
 static void dn_send_brd_hello(struct net_device *dev);
+#if 0
 static void dn_send_ptp_hello(struct net_device *dev);
+#endif
 
 static struct dn_dev_parms dn_dev_list[] =  {
 {
 	ARPHRD_ETHER, /* Ethernet */
 	DN_DEV_BCAST,
 	DN_DEV_S_RU,
-	1,
+	0,
 	1498,
-	10,
 	1,
 	10,
 	0,
@@ -76,7 +79,6 @@
 	NET_DECNET_CONF_ETHER,
 	dn_eth_up,
 	NULL,
-	NULL,
 	dn_send_brd_hello,
 	NULL
 },
@@ -84,9 +86,8 @@
 	ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
 	DN_DEV_BCAST,
 	DN_DEV_S_RU,
-	2,
+	0,
 	1400,
-	10,
 	1,
 	10,
 	0,
@@ -94,7 +95,6 @@
 	NET_DECNET_CONF_GRE,
 	NULL,
 	NULL,
-	NULL,
 	dn_send_brd_hello,
 	NULL
 },
@@ -103,9 +103,8 @@
 	ARPHRD_X25, /* Bog standard X.25 */
 	DN_DEV_UCAST,
 	DN_DEV_S_DS,
-	5,
+	0,
 	230,
-	10 * 60,
 	1,
 	120,
 	0,
@@ -113,7 +112,6 @@
 	NET_DECNET_CONF_X25,
 	NULL,
 	NULL,
-	NULL,
 	dn_send_ptp_hello,
 	NULL
 },
@@ -123,9 +121,8 @@
 	ARPHRD_PPP, /* DECnet over PPP */
 	DN_DEV_BCAST,
 	DN_DEV_S_RU,
-	5,
+	0,
 	230,
-	10,
 	1,
 	10,
 	0,
@@ -133,7 +130,6 @@
 	NET_DECNET_CONF_PPP,
 	NULL,
 	NULL,
-	NULL,
 	dn_send_brd_hello,
 	NULL
 },
@@ -143,9 +139,8 @@
 	ARPHRD_DDCMP, /* DECnet over DDCMP */
 	DN_DEV_UCAST,
 	DN_DEV_S_DS,
-	5,
+	0,
 	230,
-	10 * 60,
 	1,
 	120,
 	0,
@@ -153,7 +148,6 @@
 	NET_DECNET_CONF_DDCMP,
 	NULL,
 	NULL,
-	NULL,
 	dn_send_ptp_hello,
 	NULL
 },
@@ -164,7 +158,6 @@
 	DN_DEV_S_RU,
 	0,
 	1498,
-	10,
 	1,
 	10,
 	0,
@@ -172,7 +165,6 @@
 	NET_DECNET_CONF_LOOPBACK,
 	NULL,
 	NULL,
-	NULL,
 	dn_send_brd_hello,
 	NULL
 }
@@ -188,22 +180,20 @@
 static int max_t2[] = { 60 }; /* No max specified, but this seems sensible */
 static int min_t3[] = { 1 };
 static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MULT or T3MULT */
-#ifdef CONFIG_DECNET_ROUTER
-static int min_t1[] = { 1 };
-static int max_t1[] = { 8191 }; /* No max specified, so made it the same as t3 */
-static int min_cost[] = { 0 };
-static int max_cost[] = { 25 }; /* From DECnet spec */
+
 static int min_priority[] = { 0 };
 static int max_priority[] = { 127 }; /* From DECnet spec */
-#endif /* CONFIG_DECNET_ROUTER */
+
+static int dn_forwarding_proc(ctl_table *, int, struct file *,
+			void *, size_t *);
+static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
+			void *oldval, size_t *oldlenp,
+			void *newval, size_t newlen,
+			void **context);
 
 static struct dn_dev_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-#ifdef CONFIG_DECNET_ROUTER
-	ctl_table dn_dev_vars[6];
-#else
-	ctl_table dn_dev_vars[3];
-#endif
+	ctl_table dn_dev_vars[5];
 	ctl_table dn_dev_dev[2];
 	ctl_table dn_dev_conf_dir[2];
 	ctl_table dn_dev_proto_dir[2];
@@ -211,20 +201,16 @@
 } dn_dev_sysctl = {
 	NULL,
 	{
-#ifdef CONFIG_DECNET_ROUTER
-	{NET_DECNET_CONF_DEV_COST, "cost", (void *)DN_DEV_PARMS_OFFSET(cost),
+	{NET_DECNET_CONF_DEV_FORWARDING, "forwarding",
+	(void *)DN_DEV_PARMS_OFFSET(forwarding),
 	sizeof(int), 0644, NULL,
-	proc_dointvec_minmax, sysctl_intvec,
-	NULL, &min_cost, &max_cost},
-	{NET_DECNET_CONF_DEV_PRIORITY, "priority", (void *)DN_DEV_PARMS_OFFSET(priority),
+	dn_forwarding_proc, dn_forwarding_sysctl,
+	NULL, NULL, NULL},
+	{NET_DECNET_CONF_DEV_PRIORITY, "priority",
+	(void *)DN_DEV_PARMS_OFFSET(priority),
 	sizeof(int), 0644, NULL,
 	proc_dointvec_minmax, sysctl_intvec,
 	NULL, &min_priority, &max_priority},
-	{NET_DECNET_CONF_DEV_T1, "t1", (void *)DN_DEV_PARMS_OFFSET(t1),
-	sizeof(int), 0644, NULL,
-	proc_dointvec_minmax, sysctl_intvec,
-	NULL, &min_t1, &max_t1},
-#endif
 	{NET_DECNET_CONF_DEV_T2, "t2", (void *)DN_DEV_PARMS_OFFSET(t2),
 	sizeof(int), 0644, NULL,
 	proc_dointvec_minmax, sysctl_intvec,
@@ -274,6 +260,7 @@
 	t->dn_dev_proto_dir[0].de = NULL;
 	t->dn_dev_root_dir[0].child = t->dn_dev_proto_dir;
 	t->dn_dev_root_dir[0].de = NULL;
+	t->dn_dev_vars[0].extra1 = (void *)dev;
 
 	t->sysctl_header = register_sysctl_table(t->dn_dev_root_dir, 0);
 	if (t->sysctl_header == NULL)
@@ -291,6 +278,90 @@
 		kfree(t);
 	}
 }
+
+
+static int dn_forwarding_proc(ctl_table *table, int write, 
+				struct file *filep,
+				void *buffer, size_t *lenp)
+{
+#ifdef CONFIG_DECNET_ROUTER
+	struct net_device *dev = table->extra1;
+	struct dn_dev *dn_db;
+	int err;
+	int tmp, old;
+
+	if (table->extra1 == NULL)
+		return -EINVAL;
+
+	dn_db = dev->dn_ptr;
+	old = dn_db->parms.forwarding;
+
+	err = proc_dointvec(table, write, filep, buffer, lenp);
+
+	if ((err >= 0) && write) {
+		if (dn_db->parms.forwarding < 0)
+			dn_db->parms.forwarding = 0;
+		if (dn_db->parms.forwarding > 2)
+			dn_db->parms.forwarding = 2;
+		/*
+		 * What an ugly hack this is... its works, just. It
+		 * would be nice if sysctl/proc were just that little
+		 * bit more flexible so I don't have to write a special
+		 * routine, or suffer hacks like this - SJW
+		 */
+		tmp = dn_db->parms.forwarding;
+		dn_db->parms.forwarding = old;
+		if (dn_db->parms.down)
+			dn_db->parms.down(dev);
+		dn_db->parms.forwarding = tmp;
+		if (dn_db->parms.up)
+			dn_db->parms.up(dev);
+	}
+
+	return err;
+#else
+	return -EINVAL;
+#endif
+}
+
+static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
+			void *oldval, size_t *oldlenp,
+			void *newval, size_t newlen,
+			void **context)
+{
+#ifdef CONFIG_DECNET_ROUTER
+	struct net_device *dev = table->extra1;
+	struct dn_dev *dn_db;
+	int value;
+
+	if (table->extra1 == NULL)
+		return -EINVAL;
+
+	dn_db = dev->dn_ptr;
+
+	if (newval && newlen) {
+		if (newlen != sizeof(int))
+			return -EINVAL;
+
+		get_user(value, (int *)newval);
+		if (value < 0)
+			return -EINVAL;
+		if (value > 2)
+			return -EINVAL;
+
+		if (dn_db->parms.down)
+			dn_db->parms.down(dev);
+		dn_db->parms.forwarding = value;
+		if (dn_db->parms.up)
+			dn_db->parms.up(dev);
+	}
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
 #else /* CONFIG_SYSCTL */
 static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
 {
@@ -372,19 +443,6 @@
 	return dn_dev_insert_ifa(dn_db, ifa);
 }
 
-static struct dn_dev *dn_dev_by_index(int ifindex)
-{
-	struct net_device *dev;
-	struct dn_dev *dn_dev = NULL;
-	dev = dev_get_by_index(ifindex);
-	if (dev) {
-		dn_dev = dev->dn_ptr;
-		dev_put(dev);
-	}
-
-	return dn_dev;
-}
-
 
 int dn_dev_ioctl(unsigned int cmd, void *arg)
 {
@@ -471,6 +529,18 @@
 }
 
 #ifdef CONFIG_RTNETLINK
+static struct dn_dev *dn_dev_by_index(int ifindex)
+{
+	struct net_device *dev;
+	struct dn_dev *dn_dev = NULL;
+	dev = dev_get_by_index(ifindex);
+	if (dev) {
+		dn_dev = dev->dn_ptr;
+		dev_put(dev);
+	}
+
+	return dn_dev;
+}
 
 static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
@@ -577,39 +647,6 @@
 	netlink_broadcast(rtnl, skb, 0, RTMGRP_DECnet_IFADDR, GFP_KERNEL);
 }
 
-static int dn_dev_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
-				int type, u32 pid, u32 seq)
-{
-	struct ifinfomsg *r;
-	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
-	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
-	unsigned char priority = dn_db->parms.priority;
-	unsigned short cost = dn_db->parms.cost;
-
-	nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*r));
-	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
-	r = NLMSG_DATA(nlh);
-
-	r->ifi_family = AF_DECnet;
-	r->ifi_type   = dev->type;
-	r->ifi_index  = dev->ifindex;
-	r->ifi_flags  = dev->flags;
-	r->ifi_change = ~0U;
-
-	RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
-	RTA_PUT(skb, IFLA_COST, sizeof(unsigned short), &cost);
-	RTA_PUT(skb, IFLA_PRIORITY, sizeof(unsigned char), &priority);
-
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-rtattr_failure:
-	skb_trim(skb, b - skb->data);
-	return -1;
-}
-
 static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int idx, dn_idx;
@@ -648,45 +685,6 @@
 	return skb->len;
 }
 
-static int dn_dev_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
-{
-	int idx;
-	int s_idx = cb->args[0];
-	struct net_device *dev;
-
-	read_lock(&dev_base_lock);
-	for(dev=dev_base, idx=0; dev; dev = dev->next) {
-		if (!dev->dn_ptr)
-			continue;
-		idx++;
-		if (idx < s_idx)
-			continue;
-		if (dn_dev_fill_ifinfo(skb, dev, RTM_NEWLINK, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq) <= 0)
-			break;
-	}
-	read_unlock(&dev_base_lock);
-	cb->args[0] = idx;
-
-	return skb->len;
-}
-
-static void dn_dev_ifinfo(int type, struct net_device *dev)
-{
-	struct sk_buff *skb;
-	int size = NLMSG_GOODSIZE;
-
-	skb = alloc_skb(size, GFP_KERNEL);
-	if (!skb)
-		return;
-
-	if (dn_dev_fill_ifinfo(skb, dev, type, 0, 0) < 0) {
-		kfree_skb(skb);
-		return;
-	}
-
-	NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
-	netlink_broadcast(rtnl, skb, 0, NETLINK_CB(skb).dst_groups, GFP_KERNEL);
-}
 #endif /* CONFIG_RTNETLINK */
 
 static void dn_send_endnode_hello(struct net_device *dev)
@@ -793,7 +791,8 @@
 	*ptr++ = 0;
 	memcpy(ptr, decnet_ether_address, ETH_ALEN);
 	ptr += ETH_ALEN;
-	*ptr++ = (unsigned char)decnet_node_type;
+	*ptr++ = dn_db->parms.forwarding == 1 ? 
+			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
 	*((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize);
 	ptr += 2;
 	*ptr++ = 0; /* Priority */
@@ -829,7 +828,9 @@
 
 static void dn_send_brd_hello(struct net_device *dev)
 {
-	if (decnet_node_type == DN_RT_INFO_ENDN)
+	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
+
+	if (dn_db->parms.forwarding == 0)
 		dn_send_endnode_hello(dev);
 	else
 		dn_send_router_hello(dev);
@@ -841,14 +842,16 @@
 }
 #endif
 
+#if 0
 static void dn_send_ptp_hello(struct net_device *dev)
 {
 	int tdlen = 16;
 	int size = dev->hard_header_len + 2 + 4 + tdlen;
 	struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);
-	/* struct dn_dev *dn_db = dev->dn_ptr; */
-	unsigned char *ptr;
+	struct dn_dev *dn_db = dev->dn_ptr;
 	int i;
+	unsigned char *ptr;
+	struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
 
 	if (skb == NULL)
 		return ;
@@ -865,27 +868,24 @@
 	for(i = 0; i < tdlen; i++)
 		*ptr++ = 0252;
 
-#if 0
-	if (dn_db->router) {
-		struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
-		if (memcmp(dn->addr, decnet_ether_address, ETH_ALEN) == 0) {
-			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+	if (dn_am_i_a_router(dn, dn_db)) {
+		struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
+		if (skb2) {
 			dn_rt_finish_output(skb2, dn_rt_all_end_mcast);
 		}
 	}
-#endif
 
 	dn_rt_finish_output(skb, dn_rt_all_rt_mcast);
 }
+#endif
 
 static int dn_eth_up(struct net_device *dev)
 {
 	struct dn_dev *dn_db = dev->dn_ptr;
 
-	if (decnet_node_type == DN_RT_INFO_ENDN)
+	if (dn_db->parms.forwarding == 0)
 		dev_mc_add(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
-
-	if (decnet_node_type == DN_RT_INFO_L1RT || decnet_node_type == DN_RT_INFO_L2RT)
+	else
 		dev_mc_add(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
 
 	dev_mc_upload(dev);
@@ -902,18 +902,6 @@
 	struct net_device *dev = (struct net_device *)arg;
 	struct dn_dev *dn_db = dev->dn_ptr;
 
-#ifdef CONFIG_DECNET_ROUTER
-	if (decnet_node_type == DN_RT_INFO_L1RT || decnet_node_type == DN_RT_INFO_L2RT) {
-		if (dn_db->t1 <= dn_db->parms.t2) {
-			if (dn_db->parms.timer1)
-				dn_db->parms.timer1(dev);
-			dn_db->t1 = dn_db->parms.t1;
-		} else {
-			dn_db->t1 -= dn_db->parms.t2;
-		}
-	}
-#endif /* CONFIG_DECNET_ROUTER */
-
 	if (dn_db->t3 <= dn_db->parms.t2) {
 		if (dn_db->parms.timer3)
 			dn_db->parms.timer3(dev);
@@ -929,11 +917,6 @@
 {
 	struct dn_dev *dn_db = dev->dn_ptr;
 
-#ifdef CONFIG_DECNET_ROUTER
-	if (dn_db->parms.t2 > dn_db->parms.t1)
-		dn_db->parms.t2 = dn_db->parms.t1;
-#endif
-
 	if (dn_db->parms.t2 > dn_db->parms.t3)
 		dn_db->parms.t2 = dn_db->parms.t3;
 
@@ -987,10 +970,6 @@
 
 	dn_dev_set_timer(dev);
 
-#ifdef CONFIG_RTNETLINK
-	dn_dev_ifinfo(RTM_NEWLINK, dev);
-#endif
-
 	*err = 0;
 	return dn_db;
 }
@@ -1034,10 +1013,6 @@
 	del_timer(&dn_db->timer);
 	synchronize_bh();
 
-#ifdef CONFIG_RTNETLINK
-	dn_dev_ifinfo(RTM_DELLINK, dev);
-#endif
-
 	dn_dev_sysctl_unregister(&dn_db->parms);
 
 	neigh_ifdown(&dn_neigh_table, dev);
@@ -1190,10 +1165,10 @@
 		if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL)
 			continue;
 
-                len += sprintf(buffer + len, "%-8s %1s     %04lu %04lu   %04lu %04lu   %04hu    %03d %02x    %-10s %-7s %-7s\n",
+                len += sprintf(buffer + len, "%-8s %1s     %04u %04u   %04lu %04lu   %04hu    %03d %02x    %-10s %-7s %-7s\n",
                              	dev->name ? dev->name : "???",
                              	dn_type2asc(dn_db->parms.mode),
-                             	dn_db->t1, dn_db->parms.t1,
+                             	0, 0,
 				dn_db->t3, dn_db->parms.t3,
 				dn_db->parms.blksize,
 				dn_db->parms.priority,
@@ -1229,13 +1204,14 @@
 {
 	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
-	{ NULL,			dn_dev_dump_ifinfo,	},
+	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
 
 	{ dn_dev_rtm_newaddr,	NULL,			},
 	{ dn_dev_rtm_deladdr,	NULL,			},
 	{ NULL,			dn_dev_dump_ifaddr,	},
 	{ NULL,			NULL,			},
+
 #ifdef CONFIG_DECNET_ROUTER
 	{ dn_fib_rtm_newroute,	NULL,			},
 	{ dn_fib_rtm_delroute,	NULL,			},
@@ -1252,10 +1228,17 @@
 	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
 
+#ifdef CONFIG_DECNET_ROUTER
+	{ dn_fib_rtm_newrule,	NULL,			},
+	{ dn_fib_rtm_delrule,	NULL,			},
+	{ NULL,			dn_fib_dump_rules,	},
+	{ NULL,			NULL,			}
+#else
 	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
 	{ NULL,			NULL,			},
 	{ NULL,			NULL,			}
+#endif
 };
 #endif /* CONFIG_RTNETLINK */
 
@@ -1284,8 +1267,7 @@
 #endif /* CONFIG_SYSCTL */
 }
 
-#if defined(CONFIG_DECNET_MODULE)
-void dn_dev_cleanup(void)
+void __exit dn_dev_cleanup(void)
 {
 #ifdef CONFIG_RTNETLINK
 	rtnetlink_links[PF_DECnet] = NULL;
@@ -1309,4 +1291,3 @@
 
 	dn_dev_devices_off();
 }
-#endif /* CONFIG_DECNET_MODULE */
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- v2.3.38/linux/net/decnet/dn_fib.c	Tue Nov 23 22:42:21 1999
+++ linux/net/decnet/dn_fib.c	Sat Jan  8 21:36:20 2000
@@ -3,13 +3,15 @@
  *              operating system.  DECnet is implemented using the  BSD Socket
  *              interface as the means of communication with the user level.
  *
- *              DECnet Routing Forwarding Information Base
+ *              DECnet Routing Forwarding Information Base (Glue/Info List)
  *
  * Author:      Steve Whitehouse <SteveW@ACM.org>
  *
  *
  * Changes:
  *              Alexey Kuznetsov : SMP locking changes
+ *              Steve Whitehouse : Rewrote it... Well to be more correct, I
+ *                                 copied most of it from the ipv4 fib code.
  *
  */
 #include <linux/config.h>
@@ -30,451 +32,376 @@
 #include <net/neighbour.h>
 #include <net/dst.h>
 #include <net/dn.h>
+#include <net/dn_route.h>
 #include <net/dn_fib.h>
 #include <net/dn_neigh.h>
 #include <net/dn_dev.h>
 
-/*
- * N.B. Some of the functions here should really be inlines, but
- * I'll sort out that when its all working properly, for now the
- * stack frames will be useful for debugging.
- */
-#define DN_NUM_TABLES 255
-#define DN_MIN_TABLE  1
-#define DN_L1_TABLE 1
-#define DN_L2_TABLE 2
-
-#ifdef CONFIG_RTNETLINK
-static int dn_fib_table_dump(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
-static void dn_rtmsg_fib(int event, int table, struct dn_fib_action *fa, struct nlmsghdr *nlh, struct netlink_skb_parms *req);
-extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
-#endif /* CONFIG_RTNETLINK */
-
-static void dn_fib_del_tree(struct dn_fib_table *t);
 
-static struct dn_fib_table *dn_fib_tables[DN_NUM_TABLES + 1];
-static int dn_fib_allocs = 0;
-static int dn_fib_actions = 0;
+#define for_fib_info() { struct dn_fib_info *fi;\
+	for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
+#define endfor_fib_info() }
 
-static struct dn_fib_node *dn_fib_alloc(void)
-{
-	struct dn_fib_node *fn;
+#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
+	for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
 
-	fn = kmalloc(sizeof(struct dn_fib_node), GFP_KERNEL);
+#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\
+	for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
 
-	if (fn) {
-		memset(fn, 0, sizeof(struct dn_fib_node));
-		dn_fib_allocs++;
-	}
+#define endfor_nexthops(fi) }
 
-	return fn;
-}
+#ifdef CONFIG_RTNETLINK
+extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
+#endif /* CONFIG_RTNETLINK */
 
 
-static __inline__ void dn_fib_free(struct dn_fib_node *fn)
-{
-	kfree_s(fn, sizeof(struct dn_fib_node));
-	dn_fib_allocs--;
-}
+static struct dn_fib_info *dn_fib_info_list = NULL;
+static rwlock_t dn_fib_info_lock = RW_LOCK_UNLOCKED;
+int dn_fib_info_cnt;
+
+static struct
+{
+	int error;
+	u8 scope;
+} dn_fib_props[RTA_MAX+1] = {
+	{ 0, RT_SCOPE_NOWHERE },		/* RTN_UNSPEC */
+	{ 0, RT_SCOPE_UNIVERSE },		/* RTN_UNICAST */
+	{ 0, RT_SCOPE_HOST },			/* RTN_LOCAL */
+	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_BROADCAST */
+	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_ANYCAST */
+	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_MULTICAST */
+	{ -EINVAL, RT_SCOPE_UNIVERSE },		/* RTN_BLACKHOLE */
+	{ -EHOSTUNREACH, RT_SCOPE_UNIVERSE },	/* RTN_UNREACHABLE */
+	{ -EACCES, RT_SCOPE_UNIVERSE },		/* RTN_PROHIBIT */
+	{ -EAGAIN, RT_SCOPE_UNIVERSE },		/* RTN_THROW */
+	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_NAT */
+	{ -EINVAL, RT_SCOPE_NOWHERE }		/* RTN_XRESOLVE */
+};
 
-static struct dn_fib_action *dn_fib_new_action(void)
+void dn_fib_free_info(struct dn_fib_info *fi)
 {
-	struct dn_fib_action *fa;
-
-	fa = kmalloc(sizeof(struct dn_fib_action), GFP_KERNEL);
-
-	if (fa) {
-		memset(fa, 0, sizeof(struct dn_fib_action));
-		dn_fib_actions++;
+	if (fi->fib_dead == 0) {
+		printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");
+		return;
 	}
 
-	return fa;
+	change_nexthops(fi) {
+		if (nh->nh_dev)
+			dev_put(nh->nh_dev);
+		nh->nh_dev = NULL;
+	} endfor_nexthops(fi);
+	dn_fib_info_cnt--;
+	kfree(fi);
 }
 
-static __inline__ void dn_fib_del_action(struct dn_fib_action *fa)
+void dn_fib_release_info(struct dn_fib_info *fi)
 {
-	if ((fa->fa_type == RTN_UNICAST) && fa->fa_neigh)
-		neigh_release(fa->fa_neigh);
-
-	kfree_s(fa, sizeof(struct dn_fib_action));
-	dn_fib_actions--;
+	write_lock(&dn_fib_info_lock);
+	if (fi && --fi->fib_treeref == 0) {
+		if (fi->fib_next)
+			fi->fib_next->fib_prev = fi->fib_prev;
+		if (fi->fib_prev)
+			fi->fib_prev->fib_next = fi->fib_next;
+		if (fi == dn_fib_info_list)
+			dn_fib_info_list = fi->fib_next;
+		fi->fib_dead = 1;
+		dn_fib_info_put(fi);
+	}
+	write_unlock(&dn_fib_info_lock);
 }
 
-static struct dn_fib_node *dn_fib_follow(struct dn_fib_node *fn, dn_address key)
+static __inline__ int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
 {
-	while(fn->fn_action == NULL)
-		fn = DN_FIB_NEXT(fn, key);
+	const struct dn_fib_nh *onh = ofi->fib_nh;
 
-	return fn;
+	for_nexthops(fi) {
+		if (nh->nh_oif != onh->nh_oif ||
+			nh->nh_gw != onh->nh_gw ||
+			nh->nh_scope != onh->nh_scope ||
+			nh->nh_weight != onh->nh_weight ||
+			((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
+				return -1;
+		onh++;
+	} endfor_nexthops(fi);
+	return 0;
 }
 
-
-static struct dn_fib_node *dn_fib_follow1(struct dn_fib_node *fn, dn_address key)
+static __inline__ struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
 {
-	while((fn->fn_action == NULL) && (((key ^ fn->fn_key) >> fn->fn_shift) == 0))
-		fn = DN_FIB_NEXT(fn, key);
-
-	return fn;
+	for_fib_info() {
+		if (fi->fib_nhs != nfi->fib_nhs)
+			continue;
+		if (nfi->fib_protocol == fi->fib_protocol &&
+			nfi->fib_prefsrc == fi->fib_prefsrc &&
+			nfi->fib_priority == fi->fib_priority &&
+			((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
+			(nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
+				return fi;
+	} endfor_fib_info();
+	return NULL;
 }
 
-
-static int dn_fib_table_insert1(struct dn_fib_table *t, struct dn_fib_node *leaf)
+u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
 {
-	struct dn_fib_node *fn, *fn1, *fn2;
-	int shift = -1;
-	dn_address match;
-	dn_address cmpmask = 1;
-
-	if (!t->root) {
-		t->root = leaf;
-		t->count++;
-		return 0;
-	}
-
-	fn1 = dn_fib_follow1(t->root, leaf->fn_key);
-	fn2 = fn1->fn_up;
-
-	if (fn1->fn_key == leaf->fn_key)
-		return -EEXIST;
-
-	if ((fn = dn_fib_alloc()) == NULL)
-		return -ENOBUFS;
-
-	fn->fn_key = leaf->fn_key;
-	match = fn1->fn_key ^ fn->fn_key;
-
-	while(match) {
-		match >>= 1;
-		shift++;
-	}
-	cmpmask <<= shift;
-
-	fn->fn_cmpmask = cmpmask;
-	fn->fn_shift   = shift;
-
-	if (fn2) {
-		DN_FIB_NEXT(fn2, fn->fn_key) = fn;
-	} else {
-		t->root = fn;
+	while(RTA_OK(attr,attrlen)) {
+		if (attr->rta_type == type)
+			return *(u16*)RTA_DATA(attr);
+		attr = RTA_NEXT(attr, attrlen);
 	}
 
-	t->count++;
-	fn->fn_up = fn2;
-	DN_FIB_NEXT(fn, fn1->fn_key)  = fn1;
-	DN_FIB_NEXT(fn, leaf->fn_key) = leaf;
-
 	return 0;
 }
 
-static __inline__ int dn_maskcmp(dn_address m1, dn_address m2)
+static int dn_fib_count_nhs(struct rtattr *rta)
 {
-	int cmp = 0;
+	int nhs = 0;
+	struct rtnexthop *nhp = RTA_DATA(rta);
+	int nhlen = RTA_PAYLOAD(rta);
 
-	while(m1 || m2) {
-		if (m1 & 0x8000)
-			cmp++;
-		if (m2 & 0x8000)
-			cmp--;
-		m1 <<= 1;
-		m2 <<= 1;
+	while(nhlen >= (int)sizeof(struct rtnexthop)) {
+		if ((nhlen -= nhp->rtnh_len) < 0)
+			return 0;
+		nhs++;
+		nhp = RTNH_NEXT(nhp);
 	}
 
-	return cmp;
+	return nhs;
 }
 
-
-static int dn_fib_table_insert(struct dn_fib_table *t, struct dn_fib_action *fa)
+static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
 {
-	struct dn_fib_node *fn;
-	struct dn_fib_action **fap;
-	int err;
-	int cmp;
-
-	if (t->root && ((fn = dn_fib_follow(t->root, fa->fa_key)) != NULL) && 
-			(fn->fn_key == fa->fa_key))
-		goto add_action;
+	struct rtnexthop *nhp = RTA_DATA(rta);
+	int nhlen = RTA_PAYLOAD(rta);
 
-	if ((fn = dn_fib_alloc()) == NULL)
-		return -ENOBUFS;
+	change_nexthops(fi) {
+		int attrlen = nhlen - sizeof(struct rtnexthop);
+		if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
+			return -EINVAL;
 
-	fn->fn_key = fa->fa_key;
-	fn->fn_action = fa;
+		nh->nh_flags  = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
+		nh->nh_oif    = nhp->rtnh_ifindex;
+		nh->nh_weight = nhp->rtnh_hops + 1;
 
-	if ((err = dn_fib_table_insert1(t, fn)) < 0)
-		dn_fib_free(fn);
-
-#ifdef CONFIG_RTNETLINK
-	if (!err)
-		dn_rtmsg_fib(RTM_NEWROUTE, t->n, fa, NULL, NULL);
-#endif /* CONFIG_RTNETLINK */
-
-	return err;
-
-add_action:
-	fap = &fn->fn_action;
-
-	for(; *fap; fap = &((*fap)->fa_next)) {
-		if ((cmp = dn_maskcmp((*fap)->fa_mask, fa->fa_mask)) > 0)
-			break;
-		if (cmp < 0)
-			continue;
-		if ((*fap)->fa_cost > fa->fa_cost)
-			break;
-	}
-
-	fa->fa_next = *fap;
-	*fap = fa;
-
-#ifdef CONFIG_RTNETLINK
-	dn_rtmsg_fib(RTM_NEWROUTE, t->n, fa, NULL, NULL);
-#endif /* CONFIG_RTNETLINK */
+		if (attrlen) {
+			nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+		}
+		nhp = RTNH_NEXT(nhp);
+	} endfor_nexthops(fi);
 
 	return 0;
 }
 
-static int dn_fib_table_delete1(struct dn_fib_table *t, struct dn_fib_node *fn)
-{
-	struct dn_fib_node *fn1 = fn->fn_up;
-	struct dn_fib_node *fn2;
-	struct dn_fib_node *fn3;
-
-	if (fn == t->root) {
-		t->root = NULL;
-		t->count--;
-		return 0;
-	}
-
-	if (fn1 == NULL)
-		return -EINVAL;
-
-	fn2 = fn1->fn_up;
-	fn3 = DN_FIB_NEXT(fn1, ~fn->fn_key);
 
-	if (fn2)
-		DN_FIB_NEXT(fn2, fn1->fn_key) = fn3;
-	else
-		t->root = fn3;
-
-	fn3->fn_up = fn2;
-
-	dn_fib_free(fn1);
-	t->count--;
-	return 0;
-}
-
-static int dn_fib_table_delete(struct dn_fib_table *t, struct dn_fib_action *fa)
+static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
 {
-	struct dn_fib_res res;
-	struct dn_fib_node *fn;
-	struct dn_fib_action **fap, *old;
 	int err;
 
-	res.res_type = 0;
-	res.res_addr = fa->fa_key;
-	res.res_mask = fa->fa_mask;
-	res.res_ifindex = fa->fa_ifindex;
-	res.res_proto = fa->fa_proto;
-	res.res_cost = fa->fa_cost;
-
-	if ((err = t->lookup(t, &res)) < 0)
-		return err;
-
-	fn = res.res_fn;
-	fap = &fn->fn_action; 
-	while((*fap) != res.res_fa)
-		 fap = &((*fap)->fa_next);
-	old = *fap;
-	*fap = (*fap)->fa_next;
-
-	if (fn->fn_action == NULL)
-		dn_fib_table_delete1(t, fn);
-
-	if (t->root == NULL)
-		dn_fib_del_tree(t);
+	if (nh->nh_gw) {
+		struct dn_fib_key key;
+		struct dn_fib_res res;
+
+		if (nh->nh_flags&RTNH_F_ONLINK) {
+			struct net_device *dev;
+
+			if (r->rtm_scope >= RT_SCOPE_LINK)
+				return -EINVAL;
+			if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
+				return -ENODEV;
+			if (!(dev->flags&IFF_UP))
+				return -ENETDOWN;
+			nh->nh_dev = dev;
+			atomic_inc(&dev->refcnt);
+			nh->nh_scope = RT_SCOPE_LINK;
+			return 0;
+		}
 
-#ifdef CONFIG_RTNETLINK
-	dn_rtmsg_fib(RTM_DELROUTE, t->n, old, NULL, NULL);
-#endif /* CONFIG_RTNETLINK */
+		memset(&key, 0, sizeof(key));
+		key.dst = nh->nh_gw;
+		key.oif = nh->nh_oif;
+		key.scope = r->rtm_scope + 1;
 
-	dn_fib_del_action(old);
+		if (key.scope < RT_SCOPE_LINK)
+			key.scope = RT_SCOPE_LINK;
 
-	return 0;
-}
+		if ((err = dn_fib_lookup(&key, &res)) != 0)
+			return err;
 
-static int dn_fib_search(struct dn_fib_node *fn, struct dn_fib_res *res)
-{
-	struct dn_fib_action *fa = fn->fn_action;
+		nh->nh_scope = res.scope;
+		nh->nh_oif = DN_FIB_RES_OIF(res);
+		nh->nh_dev = DN_FIB_RES_DEV(res);
+		if (nh->nh_dev)
+			atomic_inc(&nh->nh_dev->refcnt);
+		dn_fib_res_put(&res);
+	} else {
+		struct net_device *dev;
 
-	for(; fa; fa = fa->fa_next) {
-		if ((fa->fa_key ^ res->res_addr) & fa->fa_mask)
-			continue;
-		if (res->res_ifindex && (res->res_ifindex != fa->fa_ifindex))
-			continue;
-		if (res->res_mask && (res->res_mask != fa->fa_mask))
-			continue;
-		if (res->res_proto && (res->res_proto != fa->fa_proto))
-			continue;
-		if (res->res_cost && (res->res_cost != fa->fa_cost))
-			continue;
+		if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
+			return -EINVAL;
 
-		res->res_fn = fn;
-		res->res_fa = fa;
-		return 1;
+		dev = __dev_get_by_index(nh->nh_oif);
+		if (dev == NULL || dev->dn_ptr == NULL)
+			return -ENODEV;
+		if (!(dev->flags&IFF_UP))
+			return -ENETDOWN;
+		nh->nh_dev = dev;
+		atomic_inc(&nh->nh_dev->refcnt);
+		nh->nh_scope = RT_SCOPE_HOST;
 	}
 
 	return 0;
 }
 
-static int dn_fib_recurse(struct dn_fib_node *fn, struct dn_fib_res *res)
-{
-	struct dn_fib_node *fn1;
-	int err = -ENOENT;
-
-	fn1 = dn_fib_follow(fn, res->res_addr);
-
-	if (dn_fib_search(fn1, res))
-		return 0;
-
-	while((fn1 = fn1->fn_up) != fn)
-		if ((err = dn_fib_recurse(DN_FIB_NEXT(fn1, ~res->res_addr), res)) == 0)
-			break;
-
-	return err;
-}
-
-static int dn_fib_table_lookup(struct dn_fib_table *t, struct dn_fib_res *res)
-{
-	struct dn_fib_node *fn = t->root;
-	int err = -ENOENT;
-
-	if (t->root == NULL)
-		return err;
-
-	fn = dn_fib_follow(t->root, res->res_addr);
-
-	if (dn_fib_search(fn, res))
-		return 0;
-
-	while((fn = fn->fn_up) != NULL)
-		if ((err = dn_fib_recurse(DN_FIB_NEXT(fn, ~res->res_addr), res)) == 0)
-			break;
-
-	return err;
-}
 
-static int dn_fib_table_walk_recurse(struct dn_fib_walker_t *fwt, struct dn_fib_node *fn)
+struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp)
 {
-	struct dn_fib_table *t = fwt->table;
-
-	if (fn->fn_action) {
-		fwt->fxn(fwt, fn);
+	int err;
+	struct dn_fib_info *fi = NULL;
+	struct dn_fib_info *ofi;
+	int nhs = 1;
+
+	if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
+		goto err_inval;
+
+	if (rta->rta_mp) {
+		nhs = dn_fib_count_nhs(rta->rta_mp);
+		if (nhs == 0)
+			goto err_inval;
+	}
+
+	fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
+	err = -ENOBUFS;
+	if (fi == NULL)
+		goto failure;
+	memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct dn_fib_nh));
+
+	fi->fib_protocol = r->rtm_protocol;
+	fi->fib_nhs = nhs;
+	fi->fib_flags = r->rtm_flags;
+	if (rta->rta_priority)
+		fi->fib_priority = *rta->rta_priority;
+	if (rta->rta_prefsrc)
+		memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
+
+	if (rta->rta_mp) {
+		if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)
+			goto failure;
+		if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
+			goto err_inval;
+		if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))
+			goto err_inval;
+	} else {
+		struct dn_fib_nh *nh = fi->fib_nh;
+		if (rta->rta_oif)
+			nh->nh_oif = *rta->rta_oif;
+		if (rta->rta_gw)
+			memcpy(&nh->nh_gw, rta->rta_gw, 2);
+		nh->nh_flags = r->rtm_flags;
+		nh->nh_weight = 1;
+	}
+
+	if (dn_fib_props[r->rtm_type].error) {
+		if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
+			goto err_inval;
+		goto link_it;
+	}
+
+	if (r->rtm_scope > RT_SCOPE_HOST)
+		goto err_inval;
+
+	if (r->rtm_scope == RT_SCOPE_HOST) {
+		struct dn_fib_nh *nh = fi->fib_nh;
+
+		/* Local address is added */
+		if (nhs != 1 || nh->nh_gw)
+			goto err_inval;
+		nh->nh_scope = RT_SCOPE_NOWHERE;
+		nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif);
+		err = -ENODEV;
+		if (nh->nh_dev == NULL)
+			goto failure;
 	} else {
-		dn_fib_table_walk_recurse(fwt, t->root->fn_children[0]);
-		dn_fib_table_walk_recurse(fwt, t->root->fn_children[1]);
+		change_nexthops(fi) {
+			if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
+				goto failure;
+		} endfor_nexthops(fi)
 	}
 
-	return 0;
-}
-
-static int dn_fib_table_walk(struct dn_fib_walker_t *fwt)
-{
-	struct dn_fib_table *t = fwt->table;
-
-	if (t->root != NULL) {
-		if (t->root->fn_action) {
-			fwt->fxn(fwt, t->root);
-		} else {
-			dn_fib_table_walk_recurse(fwt, t->root->fn_children[0]);
-			dn_fib_table_walk_recurse(fwt, t->root->fn_children[1]);
-		}
+#if I_GET_AROUND_TO_FIXING_PREFSRC
+	if (fi->fib_prefsrc) {
+		if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
+		    memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
+			if (dn_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
+				goto err_inval;
 	}
-
-	return 0;
-}
-
-static struct dn_fib_table *dn_fib_get_tree(int n, int create)
-{
-	struct dn_fib_table *t;
-
-	if (n < DN_MIN_TABLE)
-		return NULL;
-
-	if (n > DN_NUM_TABLES)
-		return NULL;
-
-	if (dn_fib_tables[n])
-		return dn_fib_tables[n];
-
-	if (!create)
-		return NULL;
-
-	if ((t = kmalloc(sizeof(struct dn_fib_table), GFP_KERNEL)) == NULL)
-		return NULL;
-
-	dn_fib_tables[n] = t;
-	memset(t, 0, sizeof(struct dn_fib_table));
-
-	t->n = n;
-	t->insert = dn_fib_table_insert;
-	t->delete = dn_fib_table_delete;
-	t->lookup = dn_fib_table_lookup;
-	t->walk   = dn_fib_table_walk;
-#ifdef CONFIG_RTNETLINK
-	t->dump = dn_fib_table_dump;
 #endif
 
-	return t;
-}
-
-static void dn_fib_del_tree(struct dn_fib_table *t)
-{
-	dn_fib_tables[t->n] = NULL;
-
-	if (t) {
-		kfree_s(t, sizeof(struct dn_fib_table));
-	}
+link_it:
+	if ((ofi = dn_fib_find_info(fi)) != NULL) {
+		fi->fib_dead = 1;
+		dn_fib_free_info(fi);
+		ofi->fib_treeref++;
+		return ofi;
+	}
+
+	fi->fib_treeref++;
+	atomic_inc(&fi->fib_clntref);
+	write_lock(&dn_fib_info_lock);
+	fi->fib_next = dn_fib_info_list;
+	fi->fib_prev = NULL;
+	if (dn_fib_info_list)
+		dn_fib_info_list->fib_prev = fi;
+	dn_fib_info_list = fi;
+	dn_fib_info_cnt++;
+	write_unlock(&dn_fib_info_lock);
+	return fi;
+
+err_inval:
+	err = -EINVAL;
+
+failure:
+	*errp = err;
+	if (fi) {
+		fi->fib_dead = 1;
+		dn_fib_free_info(fi);
+	}
+
+	return NULL;
 }
 
 
-int dn_fib_resolve(struct dn_fib_res *res)
-{
-	int table = DN_L1_TABLE;
-	int count = 0;
-	struct dn_fib_action *fa;
-	int err;
-
-	if ((res->res_addr ^ dn_ntohs(decnet_address)) & 0xfc00)
-		table = DN_L2_TABLE;
-
-	for(;;) {
-		struct dn_fib_table *t = dn_fib_get_tree(table, 0);
-
-		if (t == NULL)
-			return -ENOENT;
-
-		if ((err = t->lookup(t, res)) < 0)
-			return err;
-
-		if ((fa = res->res_fa) == NULL)
-			return -ENOENT;
-
-		if (fa->fa_type != RTN_THROW)
-			break;
-
-		table = fa->fa_table;
+void dn_fib_select_multipath(const struct dn_fib_key *key, struct dn_fib_res *res)
+{
+	struct dn_fib_info *fi = res->fi;
+	int w;
+
+	if (fi->fib_power <= 0) {
+		int power = 0;
+		change_nexthops(fi) {
+			if (!(nh->nh_flags&RTNH_F_DEAD)) {
+				power += nh->nh_weight;
+				nh->nh_power = nh->nh_weight;
+			}
+		} endfor_nexthops(fi);
+		fi->fib_power = power;
+	}
+
+	w = jiffies % fi->fib_power;
+
+	change_nexthops(fi) {
+		if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
+			if ((w -= nh->nh_power) <= 0) {
+				nh->nh_power--;
+				fi->fib_power--;
+				res->nh_sel = nhsel;
+				return;
+			}
+		}
+	} endfor_nexthops(fi);
 
-		if (count++ > DN_NUM_TABLES)
-			return -ENOENT;
-	}
+	printk(KERN_DEBUG "DECnet: BUG! dn_fib_select_multipath\n");
+}
 
-	switch(fa->fa_type) {
-		case RTN_PROHIBIT:
-		case RTN_UNREACHABLE:
-			return -fa->fa_error;
-	}
 
-	return 0;
-}
 
 /*
  * Punt to user via netlink for example, but for now
@@ -489,72 +416,19 @@
 
 
 #ifdef CONFIG_RTNETLINK
-static int dn_fib_convert_rtm(struct dn_fib_action *fa,
-					struct rtmsg *r, struct rtattr **rta, 
-					struct nlmsghdr *n, 
-					struct netlink_skb_parms *req)
-{
-	dn_address dst, gw, mask = 0xffff;
-	int ifindex = 0;
-	struct neighbour *neigh;
-	struct net_device *dev;
-	unsigned char addr[ETH_ALEN];
-
-	if (r->rtm_family != AF_DECnet)
-		return -EINVAL;
-
-	if (rta[RTA_DST-1])
-		memcpy(&dst, RTA_DATA(rta[RTA_DST-1]), 2);
-
-	if (rta[RTA_OIF-1])
-		memcpy(&ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));
-
-	if (rta[RTA_GATEWAY-1])
-		memcpy(&gw, RTA_DATA(rta[RTA_GATEWAY-1]), 2);
-
-	fa->fa_key      = dn_ntohs(dst);
-	fa->fa_mask     = dn_ntohs(mask);
-	fa->fa_ifindex  = ifindex;
-	fa->fa_proto    = r->rtm_protocol;
-	fa->fa_type     = r->rtm_type;
-
-	switch(fa->fa_type) {
-		case RTN_UNICAST:
-			if ((dev = __dev_get_by_index(ifindex)) == NULL)
-				return -ENODEV;
-			dn_dn2eth(addr, dn_ntohs(gw));
-			if ((neigh = __neigh_lookup(&dn_neigh_table, &addr, dev, 1)) == NULL)
-				return -EHOSTUNREACH;
-			fa->fa_neigh = neigh;
-			break;
-		case RTN_THROW:
-			fa->fa_table = 0;
-			break;
-		case RTN_PROHIBIT:
-			fa->fa_error = EPERM;
-			break;
-		case RTN_UNREACHABLE:
-			fa->fa_error = EHOSTUNREACH;
-			break;
-		case RTN_BLACKHOLE:
-			fa->fa_error = EINVAL;
-			break;
-	}
-
-	return 0;
-}
 
 static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
 {
-	switch(r->rtm_type) {
-		case RTN_UNICAST:
-		case RTN_BLACKHOLE:
-		case RTN_PROHIBIT:
-		case RTN_UNREACHABLE:
-		case RTN_THROW:
-			break;
-		default:
-			return -1;
+	int i;
+
+	for(i = 1; i <= RTA_MAX; i++) {
+		struct rtattr *attr = rta[i-1];
+		if (attr) {
+			if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
+				return -EINVAL;
+			if (i != RTA_MULTIPATH && i != RTA_METRICS)
+				rta[i-1] = (struct rtattr *)RTA_DATA(attr);
+		}
 	}
 
 	return 0;
@@ -562,114 +436,36 @@
 
 int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct dn_fib_table *t;
+	struct dn_fib_table *tb;
 	struct rtattr **rta = arg;
 	struct rtmsg *r = NLMSG_DATA(nlh);
-	struct dn_fib_action *fa;
-	int err;
 
 	if (dn_fib_check_attr(r, rta))
 		return -EINVAL;
 
-	if ((fa = dn_fib_new_action()) == NULL)
-		return -ENOBUFS;
+	tb = dn_fib_get_table(r->rtm_table, 0);
+	if (tb)
+		return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
 
-	t = dn_fib_get_tree(r->rtm_table, 0);
-	if (t) {
-		if ((err = dn_fib_convert_rtm(fa, r, rta, nlh, &NETLINK_CB(skb))) < 0)  {
-			dn_fib_del_action(fa);
-			return err;
-		}
-		err = t->delete(t, fa);
-		dn_fib_del_action(fa);
-		return err;
-	}
 	return -ESRCH;
 }
 
 int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct dn_fib_table *t;
+	struct dn_fib_table *tb;
 	struct rtattr **rta = arg;
 	struct rtmsg *r = NLMSG_DATA(nlh);
-	struct dn_fib_action *fa;
-	int err;
 
 	if (dn_fib_check_attr(r, rta))
 		return -EINVAL;
 
-	if ((fa = dn_fib_new_action()) == NULL)
-		return -ENOBUFS;
+	tb = dn_fib_get_table(r->rtm_table, 1);
+	if (tb) 
+		return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
 
-	t = dn_fib_get_tree(r->rtm_table, 1);
-	if (t) {
-		if ((err = dn_fib_convert_rtm(fa, r, rta, nlh, &NETLINK_CB(skb))) < 0) {
-			dn_fib_del_action(fa);
-			return err;
-		}
-		return t->insert(t, fa);
-	}
 	return -ENOBUFS;
 }
 
-int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
-			int table, struct dn_fib_action *fa)
-{
-	struct rtmsg *rtm;
-	struct nlmsghdr *nlh;
-	unsigned char *b = skb->tail;
-
-	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm));
-	rtm = NLMSG_DATA(nlh);
-	rtm->rtm_family = AF_DECnet;
-	rtm->rtm_dst_len = 16;
-	rtm->rtm_src_len = 16;
-	rtm->rtm_tos = 0;
-	rtm->rtm_table = table;
-	rtm->rtm_type = fa->fa_type;
-	rtm->rtm_flags = 0;
-	rtm->rtm_protocol = fa->fa_proto;
-	RTA_PUT(skb, RTA_DST, 2, &fa->fa_key);
-	if (fa->fa_ifindex)
-		RTA_PUT(skb, RTA_OIF, sizeof(int), &fa->fa_ifindex);
-
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-rtattr_failure:
-        skb_trim(skb, b - skb->data);
-        return -1;
-}
-
-static void dn_rtmsg_fib(int event, int table, struct dn_fib_action *fa,
-			struct nlmsghdr *nlh, struct netlink_skb_parms *req)
-{
-	struct sk_buff *skb;
-	u32 pid = req ? req->pid : 0;
-	int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256);
-
-	skb = alloc_skb(size, GFP_KERNEL);
-	if (!skb)
-		return;
-
-	if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, table, fa) < 0) {
-		kfree_skb(skb);
-		return;
-	}
-	NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_ROUTE;
-	if (nlh->nlmsg_flags & NLM_F_ECHO)
-		atomic_inc(&skb->users);
-	netlink_broadcast(rtnl, skb, pid, RTMGRP_DECnet_ROUTE, GFP_KERNEL);
-	if (nlh->nlmsg_flags & NLM_F_ECHO)
-		netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
-}
-
-static int dn_fib_table_dump(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb)
-{
-
-	return skb->len;
-}
 
 int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
@@ -690,7 +486,7 @@
 			continue;
 		if (t > s_t)
 			memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(int));
-		tb = dn_fib_get_tree(t, 0);
+		tb = dn_fib_get_table(t, 0);
 		if (tb == NULL)
 			continue;
 		if (tb->dump(tb, skb, cb) < 0)
@@ -703,6 +499,96 @@
 }
 #endif /* CONFIG_RTNETLINK */
 
+int dn_fib_sync_down(dn_address local, struct net_device *dev, int force)
+{
+        int ret = 0;
+        int scope = RT_SCOPE_NOWHERE;
+
+        if (force)
+                scope = -1;
+
+        for_fib_info() {
+                /* 
+                 * This makes no sense for DECnet.... we will almost
+                 * certainly have more than one local address the same
+                 * over all our interfaces. It needs thinking about
+                 * some more.
+                 */
+                if (local && fi->fib_prefsrc == local) {
+                        fi->fib_flags |= RTNH_F_DEAD;
+                        ret++;
+                } else if (dev && fi->fib_nhs) {
+                        int dead = 0;
+
+                        change_nexthops(fi) {
+                                if (nh->nh_flags&RTNH_F_DEAD)
+                                        dead++;
+                                else if (nh->nh_dev == dev &&
+                                                nh->nh_scope != scope) {
+                                        nh->nh_flags |= RTNH_F_DEAD;
+                                        fi->fib_power -= nh->nh_power;
+                                        nh->nh_power = 0;
+                                        dead++;
+                                }
+                        } endfor_nexthops(fi)
+                        if (dead == fi->fib_nhs) {
+                                fi->fib_flags |= RTNH_F_DEAD;
+                                ret++;
+                        }
+                }
+        } endfor_fib_info();
+        return ret;
+}
+
+
+int dn_fib_sync_up(struct net_device *dev)
+{
+        int ret = 0;
+
+        if (!(dev->flags&IFF_UP))
+                return 0;
+
+        for_fib_info() {
+                int alive = 0;
+
+                change_nexthops(fi) {
+                        if (!(nh->nh_flags&RTNH_F_DEAD)) {
+                                alive++;
+                                continue;
+                        }
+                        if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
+                                continue;
+                        if (nh->nh_dev != dev || dev->dn_ptr == NULL)
+                                continue;
+                        alive++;
+                        nh->nh_power = 0;
+                        nh->nh_flags &= ~RTNH_F_DEAD;
+                } endfor_nexthops(fi);
+
+                if (alive == fi->fib_nhs) {
+                        fi->fib_flags &= ~RTNH_F_DEAD;
+                        ret++;
+                }
+        } endfor_fib_info();
+        return ret;
+}
+
+void dn_fib_flush(void)
+{
+        int flushed = 0;
+        struct dn_fib_table *tb;
+        int id;
+
+        for(id = DN_NUM_TABLES; id > 0; id--) {
+                if ((tb = dn_fib_get_table(id, 0)) == NULL)
+                        continue;
+                flushed += tb->flush(tb);
+        }
+
+        if (flushed)
+                dn_rt_cache_flush(-1);
+}
+
 int dn_fib_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 
@@ -720,104 +606,65 @@
 
 #ifdef CONFIG_PROC_FS
 
-struct dn_fib_procfs {
-	int len;
-	off_t pos;
-	off_t begin;
-	off_t offset;
-	int length;
-	char *buffer;
-};
-
-static int dn_proc_action_list(struct dn_fib_walker_t *fwt, struct dn_fib_node *fn)
-{
-	struct dn_fib_procfs *pinfo = (struct dn_fib_procfs *)fwt->arg;
-	struct dn_fib_action *fa;
-	char ab[DN_ASCBUF_LEN];
-
-	if (pinfo->pos > pinfo->offset + pinfo->length)
-		return 0;
-
-	for(fa = fn->fn_action; fa; fa = fa->fa_next) {
-
-		pinfo->len += sprintf(pinfo->buffer + pinfo->len,
-					"%s/%04hx %02x %02x\n", 
-					dn_addr2asc(fa->fa_key, ab),
-					fa->fa_mask,
-					fa->fa_type,
-					fa->fa_proto);
-
-		pinfo->pos = pinfo->begin + pinfo->len;
-		if (pinfo->pos < pinfo->offset) {
-			pinfo->len = 0;
-			pinfo->begin = pinfo->pos;
-		}
-		if (pinfo->pos > pinfo->offset + pinfo->length)
-			break;
-	}
-
-	return 0;
-}
-
 static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
 {
-	struct dn_fib_procfs pinfo;
-	int i;
-	struct dn_fib_table *t;
-	struct dn_fib_walker_t fwt;
+        int first = offset / 128;
+        char *ptr = buffer;
+        int count = (length + 127) / 128;
+        int len;
+        int i;
+        struct dn_fib_table *tb;
+
+        *start = buffer + (offset % 128);
+
+        if (--first < 0) {
+                sprintf(buffer, "%-127s\n", "Iface\tDest\tGW  \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
+                --count;
+                ptr += 128;
+                first = 0;
+        }
+
+
+        for(i = DN_MIN_TABLE; (i <= DN_NUM_TABLES) && (count > 0); i++) {
+                if ((tb = dn_fib_get_table(i, 0)) != NULL) {
+                        int n = tb->get_info(tb, ptr, first, count);
+                        count -= n;
+                        ptr += n * 128;
+                }
+        }
+
+        len = ptr - *start;
+        if (len >= length)
+                return length;
+        if (len >= 0)
+                return len;
 
-	pinfo.pos = 0;
-	pinfo.len = 0;
-	pinfo.begin = 0;
-	pinfo.offset = offset;
-	pinfo.length = length;
-	pinfo.buffer = buffer;
-
-	fwt.arg = &pinfo;
-	fwt.fxn = dn_proc_action_list;
-
-	start_bh_atomic();
-	for(i = 0; i < DN_NUM_TABLES; i++) {
-		if ((t = dn_fib_get_tree(i, 0)) == NULL)
-			continue;
-
-		fwt.table = t;
-		t->walk(&fwt);
-
-		if (pinfo.pos > pinfo.offset + pinfo.length)
-			break;
-	}
-	end_bh_atomic();
-
-	*start = pinfo.buffer + (pinfo.offset - pinfo.begin);
-	pinfo.len -= (pinfo.offset - pinfo.begin);
-
-	if (pinfo.len > pinfo.length) 
-		pinfo.len = pinfo.length;
-
-	return pinfo.len;
+        return 0;
 }
 
 #endif /* CONFIG_PROC_FS */
 
-#ifdef CONFIG_DECNET_MODULE
-void dn_fib_cleanup(void)
+
+void __exit dn_fib_cleanup(void)
 {
 #ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_route",0,decnet_rt_get_info);
-#endif /* CONFIG_PROC_FS */
+	proc_net_remove("decnet_route");
+#endif
+
+	dn_fib_table_cleanup();
+	dn_fib_rules_cleanup();
 }
-#endif /* CONFIG_DECNET_MODULE */
 
 
 void __init dn_fib_init(void)
 {
-	memset(dn_fib_tables, 0, DN_NUM_TABLES * sizeof(struct dn_fib_table *));
 
 #ifdef CONFIG_PROC_FS
-	proc_net_remove("decnet_route");
+	proc_net_create("decnet_route", 0, decnet_rt_get_info);
 #endif
 
+	dn_fib_table_init();
+	dn_fib_rules_init();
 }
 
 
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_neigh.c linux/net/decnet/dn_neigh.c
--- v2.3.38/linux/net/decnet/dn_neigh.c	Tue Nov 23 22:42:21 1999
+++ linux/net/decnet/dn_neigh.c	Sat Jan  8 21:36:20 2000
@@ -554,6 +554,7 @@
 	struct dn_neigh *dn;
 	struct neigh_table *tbl = &dn_neigh_table;
 	unsigned char *rs = ptr;
+	struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
 
 	read_lock_bh(&tbl->lock);
 
@@ -564,7 +565,7 @@
 			dn = (struct dn_neigh *)neigh;
 			if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
 				continue;
-			if (decnet_node_type == DN_RT_INFO_L1RT && (dn->flags & DN_NDFLAG_R2))
+			if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2))
 				continue;
 			if (t == n)
 				rs = dn_find_slot(ptr, n, dn->priority);
@@ -654,12 +655,10 @@
 #endif /* CONFIG_PROC_FS */
 }
 
-#ifdef CONFIG_DECNET_MODULE
-void dn_neigh_cleanup(void)
+void __exit dn_neigh_cleanup(void)
 {
 #ifdef CONFIG_PROC_FS
 	proc_net_remove("decnet_neigh");
 #endif /* CONFIG_PROC_FS */
 	neigh_table_clear(&dn_neigh_table);
 }
-#endif /* CONFIG_DECNET_MODULE */
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_nsp_in.c linux/net/decnet/dn_nsp_in.c
--- v2.3.38/linux/net/decnet/dn_nsp_in.c	Mon Oct 11 15:38:15 1999
+++ linux/net/decnet/dn_nsp_in.c	Sat Jan  8 21:36:20 2000
@@ -260,8 +260,6 @@
 	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
 	unsigned short reason;
 
-	/* printk(KERN_DEBUG "DECnet: discinit %d\n", skb->len); */
-
 	if (skb->len < 2)
 		goto out;
 
@@ -283,8 +281,6 @@
 	scp->addrrem = cb->src_port;
 	sk->state    = TCP_CLOSE;
 
-	/* printk(KERN_DEBUG "DECnet: discinit\n"); */
-
 	switch(scp->state) {
 		case DN_CI:
 		case DN_CD:
@@ -299,10 +295,15 @@
 			break;
 	}
 
-	if (!sk->dead)
+	if (!sk->dead) {
+		if (sk->socket->state != SS_UNCONNECTED)
+			sk->socket->state = SS_DISCONNECTING;
 		sk->state_change(sk);
+	}
 
-	dn_destroy_sock(sk);
+	dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
+	scp->persist_fxn = dn_destroy_timer;
+	scp->persist = dn_nsp_persist(sk);
 
 out:
 	kfree_skb(skb);
@@ -343,10 +344,14 @@
 			scp->state = DN_CN;
 	}
 
-	if (!sk->dead)
+	if (!sk->dead) {
+		if (sk->socket->state != SS_UNCONNECTED)
+			sk->socket->state = SS_DISCONNECTING;
 		sk->state_change(sk);
+	}
 
-	dn_destroy_sock(sk);
+	scp->persist_fxn = dn_destroy_timer;
+	scp->persist = dn_nsp_persist(sk);
 
 out:
 	kfree_skb(skb);
@@ -519,6 +524,18 @@
 	kfree_skb(skb);
 }
 
+static void dn_nsp_no_socket(struct sk_buff *skb)
+{
+	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+
+	switch(cb->nsp_flags) {
+		case 0x28: /* Connect Confirm */
+			dn_nsp_return_disc(skb, NSP_DISCCONF, NSP_REASON_NL);
+	}
+
+	kfree_skb(skb);
+}
+
 static int dn_nsp_rx_packet(struct sk_buff *skb)
 {
 	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
@@ -615,6 +632,8 @@
 
 		return ret;
 	}
+
+	dn_nsp_no_socket(skb);
 	return 1;
 
 free_out:
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_nsp_out.c linux/net/decnet/dn_nsp_out.c
--- v2.3.38/linux/net/decnet/dn_nsp_out.c	Thu Aug 26 13:05:45 1999
+++ linux/net/decnet/dn_nsp_out.c	Sat Jan  8 21:36:20 2000
@@ -18,6 +18,7 @@
  *    Steve Whitehouse:  Fixes to check alloc'd skbs are non NULL!
  *                       Moved output state machine into one function
  *    Steve Whitehouse:  New output state machine
+ *         Paul Koning:  Connect Confirm message fix.
  */
 
 /******************************************************************************
@@ -463,14 +464,24 @@
 		dn_nsp_send_data_ack(sk);
 }
 
-void dn_send_conn_conf (struct sock *sk)
+static int dn_nsp_retrans_conn_conf(struct sock *sk)
+{
+	struct dn_scp *scp = &sk->protinfo.dn;
+
+	if (scp->state == DN_CC)
+		dn_send_conn_conf(sk, GFP_ATOMIC);
+
+	return 0;
+}
+
+void dn_send_conn_conf(struct sock *sk, int gfp)
 {
 	struct dn_scp *scp = &sk->protinfo.dn;
 	struct sk_buff *skb = NULL;
         struct nsp_conn_init_msg *msg;
-	unsigned short int aux;
+	unsigned char len = scp->conndata_out.opt_optl;
 
-	if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, GFP_KERNEL)) == NULL)
+	if ((skb = dn_alloc_skb(sk, 50 + scp->conndata_out.opt_optl, gfp)) == NULL)
 		return;
 
         msg = (struct nsp_conn_init_msg *)skb_put(skb, sizeof(*msg));
@@ -481,46 +492,89 @@
         msg->info = 0x03;
         msg->segsize = dn_htons(0x05B3);
 
-	if (scp->conndata_out.opt_optl > 0) {
-		aux = scp->conndata_out.opt_optl;
-		*skb_put(skb,1) = aux;
-		memcpy(skb_put(skb, aux), scp->conndata_out.opt_data, aux);
-	}
+	*skb_put(skb,1) = len;
+
+	if (len > 0) 
+		memcpy(skb_put(skb, len), scp->conndata_out.opt_data, len);
 	
 
-	dn_nsp_send(skb);	
+	dn_nsp_send(skb);
+
+	scp->persist = dn_nsp_persist(sk);
+	scp->persist_fxn = dn_nsp_retrans_conn_conf;
 }
 
-void dn_send_disc (struct sock *sk, unsigned char msgflg, unsigned short reason)
+
+static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, 
+			unsigned short reason, int gfp, struct dst_entry *dst,
+			int ddl, unsigned char *dd, __u16 rem, __u16 loc)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
 	struct sk_buff *skb = NULL;
-	int ddl = (msgflg == NSP_DISCINIT || msgflg == 0x38) ? (1 + scp->discdata_out.opt_optl) : 0;
-	int size = 7 + ddl;
+	int size = 7 + (ddl ? (ddl + 1) : 0);
 	unsigned char *msg;
 
-	if ((skb = dn_alloc_skb(sk, size, GFP_ATOMIC)) == NULL)
+	if ((dst == NULL) || (rem == 0)) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", (unsigned)rem, dst);
+		return;
+	}
+
+	if ((skb = dn_alloc_skb(sk, size, gfp)) == NULL)
 		return;
 
-	if (reason == 0) reason = scp->discdata_out.opt_status;
-	
 	msg = skb_put(skb, size);
 	*msg++ = msgflg;
-	*(__u16 *)msg = scp->addrrem;
+	*(__u16 *)msg = rem;
 	msg += 2;
-	*(__u16 *)msg = scp->addrloc;
+	*(__u16 *)msg = loc;
 	msg += 2;
 	*(__u16 *)msg = dn_htons(reason);
 	msg += 2;
 
 	if (ddl) {
-		*msg++ = scp->discdata_out.opt_optl;
-		memcpy(msg, scp->discdata_out.opt_data, scp->discdata_out.opt_optl);
+		*msg++ = ddl;
+		memcpy(msg, dd, ddl);
 	}
 
-	dn_nsp_send(skb);	
+	/*
+	 * This doesn't go via the dn_nsp_send() fucntion since we need
+	 * to be able to send disc packets out which have no socket
+	 * associations.
+	 */
+	skb->dst = dst_clone(dst);
+	skb->dst->output(skb);
+}
+
+
+void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg, 
+			unsigned short reason, int gfp)
+{
+	struct dn_scp *scp = &sk->protinfo.dn;
+	int ddl = 0;
+
+	if (msgflg == NSP_DISCINIT)
+		ddl = scp->discdata_out.opt_optl;
+
+	if (reason == 0)
+		reason = scp->discdata_out.opt_status;
+
+	dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->dst_cache, ddl, 
+		scp->discdata_out.opt_data, scp->addrrem, scp->addrloc);
 }
 
+
+void dn_nsp_return_disc(struct sk_buff *skb, unsigned char msgflg, 
+			unsigned short reason)
+{
+	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+	int ddl = 0;
+	int gfp = GFP_ATOMIC;
+
+	dn_nsp_do_disc(NULL, msgflg, reason, gfp, skb->dst, ddl, 
+			NULL, cb->src_port, cb->dst_port);
+}
+
+
 void dn_nsp_send_lnk(struct sock *sk, unsigned short flgs)
 {
 	struct dn_scp *scp = &sk->protinfo.dn;
@@ -543,8 +597,6 @@
 	msg1->segnum = dn_htons(cb->segnum = (scp->numoth++ & 0x0FFF));
         msg1->lsflgs = flgs;
 
-	/* printk(KERN_DEBUG "dn_nsp_send_lnk: %02x\n", flgs); */
-	
 	dn_nsp_queue_xmit(sk, skb, 1);
 
 	scp->persist = dn_nsp_persist(sk);
@@ -556,10 +608,8 @@
 {
 	struct dn_scp *scp = &sk->protinfo.dn;
 
-	if (scp->state == DN_CI) {
+	if (scp->state == DN_CI)
 		dn_nsp_send_conninit(sk, NSP_RCI);
-		scp->persist = dn_nsp_persist(sk);
-	}
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_route.c linux/net/decnet/dn_route.c
--- v2.3.38/linux/net/decnet/dn_route.c	Fri Jan  7 19:13:23 2000
+++ linux/net/decnet/dn_route.c	Sat Jan  8 21:36:20 2000
@@ -25,6 +25,11 @@
  *              Steve Whitehouse : Dave Miller's dynamic hash table sizing and
  *                                 Alexey Kuznetsov's finer grained locking
  *                                 from ipv4/route.c.
+ *              Steve Whitehouse : Routing is now starting to look like a
+ *                                 sensible set of code now, mainly due to
+ *                                 my copying the IPv4 routing code. The
+ *                                 hooks here are modified and will continue
+ *                                 to evolve for a while.
  */
 
 /******************************************************************************
@@ -82,17 +87,23 @@
 
 static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00};
 
+int dn_rt_min_delay = 2*HZ;
+int dn_rt_max_delay = 10*HZ;
+static unsigned long dn_rt_deadline = 0;
+
 static int dn_dst_gc(void);
 static struct dst_entry *dn_dst_check(struct dst_entry *, __u32);
 static struct dst_entry *dn_dst_reroute(struct dst_entry *, struct sk_buff *skb);
 static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
 static void dn_dst_link_failure(struct sk_buff *);
 static int dn_route_input(struct sk_buff *);
+static void dn_run_flush(unsigned long dummy);
 
 static struct dn_rt_hash_bucket *dn_rt_hash_table;
 static unsigned dn_rt_hash_mask;
 
 static struct timer_list dn_route_timer = { NULL, NULL, 0, 0L, NULL };
+static struct timer_list dn_rt_flush_timer = { NULL, NULL, 0, 0L, dn_run_flush };
 int decnet_dst_gc_interval = 2;
 
 static struct dst_ops dn_dst_ops = {
@@ -109,12 +120,12 @@
 	ATOMIC_INIT(0)
 };
 
-static __inline__ unsigned dn_hash(unsigned short dest)
+static __inline__ unsigned dn_hash(unsigned short src, unsigned short dst)
 {
-	unsigned short tmp = dest;
-	tmp ^= (dest >> 3);
-	tmp ^= (dest >> 5);
-	tmp ^= (dest >> 10);
+	unsigned short tmp = src ^ dst;
+	tmp ^= (tmp >> 3);
+	tmp ^= (tmp >> 5);
+	tmp ^= (tmp >> 10);
 	return dn_rt_hash_mask & (unsigned)tmp;
 }
 
@@ -155,8 +166,10 @@
 	unsigned long expire = 10 * HZ;
 
 	for(i = 0; i <= dn_rt_hash_mask; i++) {
+
 		write_lock_bh(&dn_rt_hash_table[i].lock);
 		rtp = &dn_rt_hash_table[i].chain;
+
 		for(; (rt=*rtp); rtp = &rt->u.rt_next) {
 			if (atomic_read(&rt->u.dst.__refcnt) ||
 					(now - rt->u.dst.lastuse) < expire)
@@ -199,9 +212,8 @@
 	return;
 }
 
-static void dn_insert_route(struct dn_route *rt)
+static void dn_insert_route(struct dn_route *rt, unsigned hash)
 {
-	unsigned hash = dn_hash(rt->rt_daddr);
 	unsigned long now = jiffies;
 
 	write_lock_bh(&dn_rt_hash_table[hash].lock);
@@ -237,6 +249,43 @@
 	}
 }
 
+static spinlock_t dn_rt_flush_lock = SPIN_LOCK_UNLOCKED;
+
+void dn_rt_cache_flush(int delay)
+{
+	unsigned long now = jiffies;
+	int user_mode = !in_interrupt();
+
+	if (delay < 0)
+		delay = dn_rt_min_delay;
+
+	spin_lock_bh(&dn_rt_flush_lock);
+
+	if (del_timer(&dn_rt_flush_timer) && delay > 0 && dn_rt_deadline) {
+		long tmo = (long)(dn_rt_deadline - now);
+
+		if (user_mode && tmo < dn_rt_max_delay - dn_rt_min_delay)
+			tmo = 0;
+
+		if (delay > tmo)
+			delay = tmo;
+	}
+
+	if (delay <= 0) {
+		spin_unlock_bh(&dn_rt_flush_lock);
+		dn_run_flush(0);
+		return;
+	}
+
+	if (dn_rt_deadline == 0)
+		dn_rt_deadline = now + dn_rt_max_delay;
+
+	dn_rt_flush_timer.expires = now + delay;
+	add_timer(&dn_rt_flush_timer);
+	spin_unlock_bh(&dn_rt_flush_lock);
+}
+
+
 static int dn_route_rx_packet(struct sk_buff *skb)
 {
 	int err;
@@ -531,33 +580,49 @@
 	struct net_device *dev = decnet_default_device;
 	struct neighbour *neigh = NULL;
 	struct dn_dev *dn_db;
-
-
+	unsigned hash;
 #ifdef CONFIG_DECNET_ROUTER
-	if (decnet_node_type != DN_RT_INFO_ENDN) {
-		struct dn_fib_res res;
-		int err = 0;
-
-		res.res_addr = dst;
-		res.res_mask = 0;
-		res.res_ifindex = 0;
-		res.res_proto = RTN_UNSPEC;
-		res.res_cost = 0;
-
-		if ((err = dn_fib_resolve(&res)) == 0) {
-
-			if (!res.res_fa || (res.res_fa->fa_type != RTN_UNICAST))
-				return -EPROTO;
-
-			if ((neigh = neigh_clone(res.res_fa->fa_neigh)) != NULL)
-				goto got_route;
+	struct dn_fib_key key;
+	struct dn_fib_res res;
+	int err;
 
-			return -ENOBUFS;
+	key.src = src;
+	key.dst = dst;
+	key.iif = 0;
+	key.oif = 0;
+	key.fwmark = 0;
+	key.scope = RT_SCOPE_UNIVERSE;
+
+	if ((err = dn_fib_lookup(&key, &res)) == 0) {
+		switch(res.type) {
+			case RTN_UNICAST:
+				/*
+				 * This method of handling multipath
+				 * routes is a hack and will change.
+				 * It works for now though.
+				 */
+				if (res.fi->fib_nhs)
+					dn_fib_select_multipath(&key, &res);
+				neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1);
+				err = -ENOBUFS;
+				if (!neigh)
+					break;
+				err = 0;
+				break;
+			case RTN_UNREACHABLE:
+				err = -EHOSTUNREACH;
+				break;
+			default:
+				err = -EINVAL;
 		}
-
-		if (err != -ENOENT)
+		dn_fib_res_put(&res);
+		if (err < 0)
 			return err;
+		goto got_route;
 	}
+
+	if (err != -ESRCH)
+		return err;
 #endif 
 
 	/* Look in On-Ethernet cache first */
@@ -594,13 +659,16 @@
 
 	dn_db = (struct dn_dev *)neigh->dev->dn_ptr;
 	
-	rt->rt_saddr = src;
-	rt->rt_daddr = dst;
-	rt->rt_oif = neigh->dev->ifindex;
-	rt->rt_iif = 0;
+	rt->key.saddr  = src;
+	rt->rt_saddr   = src;
+	rt->key.daddr  = dst;
+	rt->rt_daddr   = dst;
+	rt->key.oif    = neigh ? neigh->dev->ifindex : -1;
+	rt->key.iif    = 0;
+	rt->key.fwmark = 0;
 
 	rt->u.dst.neighbour = neigh;
-	rt->u.dst.dev = neigh->dev;
+	rt->u.dst.dev = neigh ? neigh->dev : NULL;
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dn_output;
 	rt->u.dst.input  = dn_rt_bug;
@@ -608,7 +676,8 @@
 	if (dn_dev_islocal(neigh->dev, rt->rt_daddr))
 		rt->u.dst.input = dn_nsp_rx;
 
-	dn_insert_route(rt);
+	hash = dn_hash(rt->key.saddr, rt->key.daddr);
+	dn_insert_route(rt, hash);
 	*pprt = &rt->u.dst;
 
 	return 0;
@@ -616,16 +685,16 @@
 
 int dn_route_output(struct dst_entry **pprt, dn_address dst, dn_address src, int flags)
 {
-	unsigned hash = dn_hash(dst);
+	unsigned hash = dn_hash(src, dst);
 	struct dn_route *rt = NULL;
 
 	if (!(flags & MSG_TRYHARD)) {
 		read_lock_bh(&dn_rt_hash_table[hash].lock);
 		for(rt = dn_rt_hash_table[hash].chain; rt; rt = rt->u.rt_next) {
-			if ((dst == rt->rt_daddr) &&
-					(src == rt->rt_saddr) &&
-					(rt->rt_iif == 0) &&
-					(rt->rt_oif != 0)) {
+			if ((dst == rt->key.daddr) &&
+					(src == rt->key.saddr) &&
+					(rt->key.iif == 0) &&
+					(rt->key.oif != 0)) {
 				rt->u.dst.lastuse = jiffies;
 				dst_hold(&rt->u.dst);
 				rt->u.dst.__use++;
@@ -649,6 +718,15 @@
 	struct neighbour *neigh = NULL;
 	int (*dnrt_input)(struct sk_buff *skb);
 	int (*dnrt_output)(struct sk_buff *skb);
+	u32 fwmark = 0;
+	unsigned hash;
+	dn_address saddr = cb->src;
+	dn_address daddr = cb->dst;
+#ifdef CONFIG_DECNET_ROUTER
+	struct dn_fib_key key;
+	struct dn_fib_res res;
+	int err;
+#endif
 
 	if (dev == NULL)
 		return -EINVAL;
@@ -683,6 +761,8 @@
 	 */
 	dnrt_input  = dn_nsp_rx;
 	dnrt_output = dn_output;
+	saddr = cb->dst;
+	daddr = cb->src;
 
 	if ((neigh = neigh_lookup(&dn_neigh_table, &cb->src, dev)) != NULL)
 		goto add_entry;
@@ -705,9 +785,49 @@
 	 * Destination is another node... find next hop in
 	 * routing table here.
 	 */
-	if (decnet_node_type == DN_RT_INFO_ENDN)
+
+	key.src = cb->src;
+	key.dst = cb->dst;
+	key.iif = dev->ifindex;
+	key.oif = 0;
+	key.scope = RT_SCOPE_UNIVERSE;
+
+#ifdef CONFIG_DECNET_ROUTE_FWMASK
+	if (skb->nfreason == NF_REASON_FOR_ROUTING)
+		key.fwmark = skb->fwmark;
+	else
+		key.fwmark = 0;
+#else
+	key.fwmark = 0;
+#endif
+
+	if ((err = dn_fib_lookup(&key, &res)) == 0) {
+		switch(res.type) {
+			case RTN_UNICAST:
+				if (res.fi->fib_nhs)
+					dn_fib_select_multipath(&key, &res);
+				neigh = __neigh_lookup(&dn_neigh_table, &DN_FIB_RES_GW(res), DN_FIB_RES_DEV(res), 1);
+				err = -ENOBUFS;
+				if (!neigh)
+					break;
+				err = 0;
+				dnrt_input = dn_forward;
+				fwmark = key.fwmark;
+				break;
+			case RTN_UNREACHABLE:
+				dnrt_input = dn_blackhole;
+				fwmark = key.fwmark;
+				break;
+			default:
+				err = -EINVAL;
+		}
+		dn_fib_res_put(&res);
+		if (err < 0)
+			return err;
 		goto add_entry;
+	}
 
+	return err;
 
 #endif /* CONFIG_DECNET_ROUTER */
 
@@ -718,18 +838,22 @@
                 return -EINVAL;
         }
 
-	rt->rt_saddr = cb->dst;
-	rt->rt_daddr = cb->src;
-	rt->rt_oif = 0;
-	rt->rt_iif = dev->ifindex;
+	rt->key.saddr  = cb->src;
+	rt->rt_saddr   = saddr;
+	rt->key.daddr  = cb->dst;
+	rt->rt_daddr   = daddr;
+	rt->key.oif    = 0;
+	rt->key.iif    = dev->ifindex;
+	rt->key.fwmark = fwmark;
 
 	rt->u.dst.neighbour = neigh;
-	rt->u.dst.dev = dev;
+	rt->u.dst.dev = neigh ? neigh->dev : NULL;
 	rt->u.dst.lastuse = jiffies;
 	rt->u.dst.output = dnrt_output;
 	rt->u.dst.input = dnrt_input;
 
-	dn_insert_route(rt);
+	hash = dn_hash(rt->key.saddr, rt->key.daddr);
+	dn_insert_route(rt, hash);
 	skb->dst = (struct dst_entry *)rt;
 
 	return 0;
@@ -739,17 +863,22 @@
 {
 	struct dn_route *rt;
 	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
-	unsigned hash = dn_hash(cb->src);
+	unsigned hash = dn_hash(cb->src, cb->dst);
 
 	if (skb->dst)
 		return 0;
 
 	read_lock(&dn_rt_hash_table[hash].lock);
 	for(rt = dn_rt_hash_table[hash].chain; rt != NULL; rt = rt->u.rt_next) {
-		if ((rt->rt_saddr == cb->dst) &&
-				(rt->rt_daddr == cb->src) &&
-				(rt->rt_oif == 0) &&
-				(rt->rt_iif == cb->iif)) {
+		if ((rt->key.saddr == cb->src) &&
+				(rt->key.daddr == cb->dst) &&
+				(rt->key.oif == 0) &&
+#ifdef CONFIG_DECNET_ROUTE_FWMASK
+				(rt->key.fwmark == (skb->nfreason ==
+							NF_REASON_FOR_ROUTING
+							? skb->nfmark : 0)) &&
+#endif
+				(rt->key.iif == cb->iif)) {
 			rt->u.dst.lastuse = jiffies;
 			dst_hold(&rt->u.dst);
 			rt->u.dst.__use++;
@@ -953,6 +1082,7 @@
 					);
 
 
+
 	                pos = begin + len;
 	
         	        if (pos < offset) {
@@ -998,48 +1128,51 @@
 	for(order = 0; (1UL << order) < goal; order++)
 		/* NOTHING */;
 
-	/*
-	 * Only want 1024 entries max, since the table is very, very unlikely
-	 * to be larger than that.
-	 */
-	while(order && ((((1UL << order) * PAGE_SIZE) / 
-				sizeof(struct dn_rt_hash_bucket)) >= 2048))
-		order--;
-
-	do {
-		dn_rt_hash_mask = (1UL << order) * PAGE_SIZE /
-			sizeof(struct dn_rt_hash_bucket);
-		while(dn_rt_hash_mask & (dn_rt_hash_mask - 1))
-			dn_rt_hash_mask--;
-		dn_rt_hash_table = (struct dn_rt_hash_bucket *)
-			__get_free_pages(GFP_ATOMIC, order);
-	} while (dn_rt_hash_table == NULL && --order > 0);
+        /*
+         * Only want 1024 entries max, since the table is very, very unlikely
+         * to be larger than that.
+         */
+        while(order && ((((1UL << order) * PAGE_SIZE) / 
+                                sizeof(struct dn_rt_hash_bucket)) >= 2048))
+                order--;
+
+        do {
+                dn_rt_hash_mask = (1UL << order) * PAGE_SIZE /
+                        sizeof(struct dn_rt_hash_bucket);
+                while(dn_rt_hash_mask & (dn_rt_hash_mask - 1))
+                        dn_rt_hash_mask--;
+                dn_rt_hash_table = (struct dn_rt_hash_bucket *)
+                        __get_free_pages(GFP_ATOMIC, order);
+        } while (dn_rt_hash_table == NULL && --order > 0);
 
 	if (!dn_rt_hash_table)
-		panic("Failed to allocate DECnet route cache hash table\n");
+                panic("Failed to allocate DECnet route cache hash table\n");
 
-	printk(KERN_INFO "DECnet: Routing cache hash table of %u buckets, %dKbytes\n", dn_rt_hash_mask, (dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024);
+	printk(KERN_INFO 
+		"DECnet: Routing cache hash table of %u buckets, %dKbytes\n", 
+		dn_rt_hash_mask, 
+		(dn_rt_hash_mask*sizeof(struct dn_rt_hash_bucket))/1024);
 
 	dn_rt_hash_mask--;
-	for(i = 0; i <= dn_rt_hash_mask; i++) {
-		dn_rt_hash_table[i].lock = RW_LOCK_UNLOCKED;
-		dn_rt_hash_table[i].chain = NULL;
-	}
+        for(i = 0; i <= dn_rt_hash_mask; i++) {
+                dn_rt_hash_table[i].lock = RW_LOCK_UNLOCKED;
+                dn_rt_hash_table[i].chain = NULL;
+        }
 
-	dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
+        dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
 
 #ifdef CONFIG_PROC_FS
 	proc_net_create("decnet_cache",0,decnet_cache_get_info);
 #endif /* CONFIG_PROC_FS */
 }
 
-#ifdef CONFIG_DECNET_MODULE
-void dn_route_cleanup(void)
+void __exit dn_route_cleanup(void)
 {
 	del_timer(&dn_route_timer);
 	dn_run_flush(0);
+
 #ifdef CONFIG_PROC_FS
 	proc_net_remove("decnet_cache");
 #endif /* CONFIG_PROC_FS */
 }
-#endif /* CONFIG_DECNET_MODULE */
+
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_rules.c linux/net/decnet/dn_rules.c
--- v2.3.38/linux/net/decnet/dn_rules.c	Wed Dec 31 16:00:00 1969
+++ linux/net/decnet/dn_rules.c	Sat Jan  8 21:36:20 2000
@@ -0,0 +1,372 @@
+
+/*
+ * DECnet       An implementation of the DECnet protocol suite for the LINUX
+ *              operating system.  DECnet is implemented using the  BSD Socket
+ *              interface as the means of communication with the user level.
+ *
+ *              DECnet Routing Forwarding Information Base (Rules)
+ *
+ * Author:      Steve Whitehouse <SteveW@ACM.org>
+ *              Mostly copied from Alexey Kuznetsov's ipv4/fib_rules.c
+ *
+ *
+ * Changes:
+ *
+ */
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include <net/neighbour.h>
+#include <net/dst.h>
+#include <net/dn.h>
+#include <net/dn_fib.h>
+#include <net/dn_neigh.h>
+#include <net/dn_dev.h>
+
+struct dn_fib_rule
+{
+	struct dn_fib_rule	*r_next;
+	atomic_t		r_clntref;
+	u32			r_preference;
+	unsigned char		r_table;
+	unsigned char		r_action;
+	unsigned char		r_dst_len;
+	unsigned char		r_src_len;
+	dn_address		r_src;
+	dn_address		r_srcmask;
+	dn_address		r_dst;
+	dn_address		r_dstmask;
+	u8			r_flags;
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+	u32			r_fwmark;
+#endif
+	int			r_ifindex;
+	char			r_ifname[IFNAMSIZ];
+	int			r_dead;
+};
+
+static struct dn_fib_rule default_rule = { NULL, ATOMIC_INIT(2), 0x7fff, DN_DEFAULT_TABLE, RTN_UNICAST };
+
+static struct dn_fib_rule *dn_fib_rules = &default_rule;
+static rwlock_t dn_fib_rules_lock = RW_LOCK_UNLOCKED;
+
+
+int dn_fib_rtm_delrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+	struct rtattr **rta = arg;
+	struct rtmsg *rtm = NLMSG_DATA(nlh);
+	struct dn_fib_rule *r, **rp;
+	int err = -ESRCH;
+
+	for(rp=&dn_fib_rules; (r=*rp) != NULL; rp = &r->r_next) {
+		if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 2) == 0) &&
+			rtm->rtm_src_len == r->r_src_len &&
+			rtm->rtm_dst_len == r->r_dst_len &&
+			(!rta[RTA_DST-1] || memcmp(RTA_DATA(rta[RTA_DST-1]), &r->r_dst, 2) == 0) &&
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+			(!rta[RTA_PROTOINFO-1] || memcmp(RTA_DATA(rta[RTA_PROTOINFO-1]), &r->r_fwmark, 4) == 0) &&
+#endif
+			(!rtm->rtm_type || rtm->rtm_type == r->r_action) &&
+			(!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
+			(!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) &&
+			(!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
+
+			err = -EPERM;
+			if (r == &default_rule)
+				break;
+
+			write_lock_bh(&dn_fib_rules_lock);
+			*rp = r->r_next;
+			r->r_dead = 1;
+			write_unlock_bh(&dn_fib_rules_lock);
+			dn_fib_rule_put(r);
+			err = 0;
+			break;
+		}
+	}
+
+	return err;
+}
+
+void dn_fib_rule_put(struct dn_fib_rule *r)
+{
+	if (atomic_dec_and_test(&r->r_clntref)) {
+		if (r->r_dead)
+			kfree(r);
+		else
+			printk(KERN_DEBUG "Attempt to free alive dn_fib_rule\n");
+	}
+}
+
+
+int dn_fib_rtm_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+	struct rtattr **rta = arg;
+	struct rtmsg *rtm = NLMSG_DATA(nlh);
+	struct dn_fib_rule *r, *new_r, **rp;
+	unsigned char table_id;
+
+	if (rtm->rtm_src_len > 16 || rtm->rtm_dst_len > 16)
+		return -EINVAL;
+
+	if (rta[RTA_IIF-1] && RTA_PAYLOAD(rta[RTA_IIF-1]) > IFNAMSIZ)
+		return -EINVAL;
+
+	if (rtm->rtm_type == RTN_NAT)
+		return -EINVAL;
+
+	table_id = rtm->rtm_table;
+	if (table_id == RT_TABLE_UNSPEC) {
+		struct dn_fib_table *tb;
+		if (rtm->rtm_type == RTN_UNICAST) {
+			if ((tb = dn_fib_empty_table()) == NULL)
+				return -ENOBUFS;
+			table_id = tb->n;
+		}
+	}
+
+	new_r = kmalloc(sizeof(*new_r), GFP_KERNEL);
+	if (!new_r)
+		return -ENOMEM;
+	memset(new_r, 0, sizeof(*new_r));
+	if (rta[RTA_SRC-1])
+		memcpy(&new_r->r_src, RTA_DATA(rta[RTA_SRC-1]), 2);
+	if (rta[RTA_DST-1])
+		memcpy(&new_r->r_dst, RTA_DATA(rta[RTA_DST-1]), 2);
+	new_r->r_src_len = rtm->rtm_src_len;
+	new_r->r_dst_len = rtm->rtm_dst_len;
+	new_r->r_srcmask = dnet_make_mask(rtm->rtm_src_len);
+	new_r->r_dstmask = dnet_make_mask(rtm->rtm_dst_len);
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+	if (rta[RTA_PROTOINFO-1])
+		memcpy(&new_r->r_fwmark, RTA_DATA(rta[RTA_PROTOINFO-1]), 4);
+#endif
+	new_r->r_action = rtm->rtm_type;
+	new_r->r_flags = rtm->rtm_flags;
+	if (rta[RTA_PRIORITY-1])
+		memcpy(&new_r->r_preference, RTA_DATA(rta[RTA_PRIORITY-1]), 4);
+	new_r->r_table = table_id;
+	if (rta[RTA_IIF-1]) {
+		struct net_device *dev;
+		memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
+		new_r->r_ifname[IFNAMSIZ-1] = 0;
+		new_r->r_ifindex = -1;
+		dev = __dev_get_by_name(new_r->r_ifname);
+		if (dev)
+			new_r->r_ifindex = dev->ifindex;
+	}
+
+	rp = &dn_fib_rules;
+	if (!new_r->r_preference) {
+		r = dn_fib_rules;
+		if (r && (r = r->r_next) != NULL) {
+			rp = &dn_fib_rules->r_next;
+			if (r->r_preference)
+				new_r->r_preference = r->r_preference - 1;
+		}
+	}
+
+	while((r=*rp) != NULL) {
+		if (r->r_preference > new_r->r_preference)
+			break;
+		rp = &r->r_next;
+	}
+
+	new_r->r_next = r;
+	atomic_inc(&new_r->r_clntref);
+	write_lock_bh(&dn_fib_rules_lock);
+	*rp = new_r;
+	write_unlock_bh(&dn_fib_rules_lock);
+	return 0;
+}
+
+
+int dn_fib_lookup(struct dn_fib_key *key, struct dn_fib_res *res)
+{
+	struct dn_fib_rule *r, *policy;
+	struct dn_fib_table *tb;
+	dn_address saddr = key->src;
+	dn_address daddr = key->dst;
+	int err;
+
+	read_lock(&dn_fib_rules_lock);
+	for(r = dn_fib_rules; r; r = r->r_next) {
+		if (((saddr^r->r_src) & r->r_srcmask) ||
+		    ((daddr^r->r_dst) & r->r_dstmask) ||
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+		    (r->r_fwmark && r->r_fwmark != key->fwmark) ||
+#endif
+		    (r->r_ifindex && r->r_ifindex != key->iif))
+			continue;
+
+		switch(r->r_action) {
+			case RTN_UNICAST:
+				policy = r;
+				break;
+			case RTN_UNREACHABLE:
+				read_unlock(&dn_fib_rules_lock);
+				return -ENETUNREACH;
+			default:
+			case RTN_BLACKHOLE:
+				read_unlock(&dn_fib_rules_lock);
+				return -EINVAL;
+			case RTN_PROHIBIT:
+				read_unlock(&dn_fib_rules_lock);
+				return -EACCES;
+		}
+
+		if ((tb = dn_fib_get_table(r->r_table, 0)) == NULL)
+			continue;
+		err = tb->lookup(tb, key, res);
+		if (err == 0) {
+			res->r = policy;
+			if (policy)
+				atomic_inc(&policy->r_clntref);
+			read_unlock(&dn_fib_rules_lock);
+			return 0;
+		}
+		if (err < 0 && err != -EAGAIN) {
+			read_unlock(&dn_fib_rules_lock);
+			return err;
+		}
+	}
+
+	read_unlock(&dn_fib_rules_lock);
+	return -ESRCH;
+}
+
+static void dn_fib_rules_detach(struct net_device *dev)
+{
+	struct dn_fib_rule *r;
+
+	for(r = dn_fib_rules; r; r = r->r_next) {
+		if (r->r_ifindex == dev->ifindex) {
+			write_lock_bh(&dn_fib_rules_lock);
+			r->r_ifindex = -1;
+			write_unlock_bh(&dn_fib_rules_lock);
+		}
+	}
+}
+
+static void dn_fib_rules_attach(struct net_device *dev)
+{
+	struct dn_fib_rule *r;
+
+	for(r = dn_fib_rules; r; r = r->r_next) {
+		if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) {
+			write_lock_bh(&dn_fib_rules_lock);
+			r->r_ifindex = dev->ifindex;
+			write_unlock_bh(&dn_fib_rules_lock);
+		}
+	}
+}
+
+static int dn_fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	switch(event) {
+		case NETDEV_UNREGISTER:
+			dn_fib_rules_detach(dev);
+			dn_fib_sync_down(0, dev, 1);
+		case NETDEV_REGISTER:
+			dn_fib_rules_attach(dev);
+			dn_fib_sync_up(dev);
+	}
+
+	return NOTIFY_DONE;
+}
+
+
+static struct notifier_block dn_fib_rules_notifier = {
+	dn_fib_rules_event,
+	NULL,
+	0
+};
+
+#ifdef CONFIG_RTNETLINK
+
+static int dn_fib_fill_rule(struct sk_buff *skb, struct dn_fib_rule *r, struct netlink_callback *cb)
+{
+	struct rtmsg *rtm;
+	struct nlmsghdr *nlh;
+	unsigned char *b = skb->tail;
+
+
+	nlh = NLMSG_PUT(skb, NETLINK_CREDS(cb->skb)->pid, cb->nlh->nlmsg_seq, RTM_NEWRULE, sizeof(*rtm));
+	rtm = NLMSG_DATA(nlh);
+	rtm->rtm_family = AF_DECnet;
+	rtm->rtm_dst_len = r->r_dst_len;
+	rtm->rtm_src_len = r->r_src_len;
+	rtm->rtm_tos = 0;
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+	if (r->r_fwmark)
+		RTA_PUT(skb, RTA_PROTOINFO, 4, &r->r_fwmark);
+#endif
+	rtm->rtm_table = r->r_table;
+	rtm->rtm_protocol = 0;
+	rtm->rtm_scope = 0;
+	rtm->rtm_type = r->r_action;
+	rtm->rtm_flags = r->r_flags;
+
+	if (r->r_dst_len)
+		RTA_PUT(skb, RTA_DST, 2, &r->r_dst);
+	if (r->r_src_len)
+		RTA_PUT(skb, RTA_SRC, 2, &r->r_src);
+	if (r->r_ifname[0])
+		RTA_PUT(skb, RTA_IIF, IFNAMSIZ, &r->r_ifname);
+	if (r->r_preference)
+		RTA_PUT(skb, RTA_PRIORITY, 4, &r->r_preference);
+	nlh->nlmsg_len = skb->tail - b;
+	return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+	skb_put(skb, b - skb->tail);
+	return -1;
+}
+
+int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	int idx;
+	int s_idx = cb->args[0];
+	struct dn_fib_rule *r;
+
+	read_lock(&dn_fib_rules_lock);
+	for(r = dn_fib_rules, idx = 0; r; r = r->r_next, idx++) {
+		if (idx < s_idx)
+			continue;
+		if (dn_fib_fill_rule(skb, r, cb) < 0)
+			break;
+	}
+	read_unlock(&dn_fib_rules_lock);
+	cb->args[0] = idx;
+
+	return skb->len;
+}
+
+#endif /* CONFIG_RTNETLINK */
+
+void __init dn_fib_rules_init(void)
+{
+	register_netdevice_notifier(&dn_fib_rules_notifier);
+}
+
+void __exit dn_fib_rules_cleanup(void)
+{
+	unregister_netdevice_notifier(&dn_fib_rules_notifier);
+}
+
+
diff -u --recursive --new-file v2.3.38/linux/net/decnet/dn_table.c linux/net/decnet/dn_table.c
--- v2.3.38/linux/net/decnet/dn_table.c	Wed Dec 31 16:00:00 1969
+++ linux/net/decnet/dn_table.c	Sat Jan  8 21:36:20 2000
@@ -0,0 +1,907 @@
+/*
+ * DECnet       An implementation of the DECnet protocol suite for the LINUX
+ *              operating system.  DECnet is implemented using the  BSD Socket
+ *              interface as the means of communication with the user level.
+ *
+ *              DECnet Routing Forwarding Information Base (Routing Tables)
+ *
+ * Author:      Steve Whitehouse <SteveW@ACM.org>
+ *              Mostly copied from the IPv4 routing code
+ *
+ *
+ * Changes:
+ *
+ */
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include <linux/route.h> /* RTF_xxx */
+#include <net/neighbour.h>
+#include <net/dst.h>
+#include <net/dn.h>
+#include <net/dn_route.h>
+#include <net/dn_fib.h>
+#include <net/dn_neigh.h>
+#include <net/dn_dev.h>
+
+struct dn_zone
+{
+	struct dn_zone		*dz_next;
+	struct dn_fib_node 	**dz_hash;
+	int			dz_nent;
+	int			dz_divisor;
+	u32			dz_hashmask;
+#define DZ_HASHMASK(dz)	((dz)->dz_hashmask)
+	int			dz_order;
+	u32			dz_mask;
+#define DZ_MASK(dz)	((dz)->dz_mask)
+};
+
+struct dn_hash
+{
+	struct dn_zone	*dh_zones[17];
+	struct dn_zone	*dh_zone_list;
+};
+
+#define dz_key_0(key)		((key).datum = 0)
+#define dz_prefix(key,dz)	((key).datum)
+
+#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
+        for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
+
+#define endfor_nexthops(fi) }
+
+#define DN_MAX_DIVISOR 1024
+#define DN_S_ZOMBIE 1
+#define DN_S_ACCESSED 2
+
+#define DN_FIB_SCAN(f, fp) \
+for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
+
+#define DN_FIB_SCAN_KEY(f, fp, key) \
+for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
+
+
+static rwlock_t dn_fib_tables_lock = RW_LOCK_UNLOCKED;
+static struct dn_fib_table *dn_fib_tables[DN_NUM_TABLES + 1];
+
+static kmem_cache_t *dn_hash_kmem;
+static int dn_fib_hash_zombies = 0;
+
+static __inline__ dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz)
+{
+	u32 h = ntohs(key.datum)>>(16 - dz->dz_order);
+	h ^= (h >> 10);
+	h ^= (h >> 6);
+	h ^= (h >> 3);
+	h &= DZ_HASHMASK(dz);
+	return *(dn_fib_idx_t *)&h;
+}
+
+static __inline__ dn_fib_key_t dz_key(u16 dst, struct dn_zone *dz)
+{
+	dn_fib_key_t k;
+	k.datum = dst & DZ_MASK(dz);
+	return k;
+}
+
+static __inline__ struct dn_fib_node **dn_chain_p(dn_fib_key_t key, struct dn_zone *dz)
+{
+	return &dz->dz_hash[dn_hash(key, dz).datum];
+}
+
+static __inline__ struct dn_fib_node *dz_chain(dn_fib_key_t key, struct dn_zone *dz)
+{
+	return dz->dz_hash[dn_hash(key, dz).datum];
+}
+
+static __inline__ int dn_key_eq(dn_fib_key_t a, dn_fib_key_t b)
+{
+	return a.datum == b.datum;
+}
+
+static __inline__ int dn_key_leq(dn_fib_key_t a, dn_fib_key_t b)
+{
+	return a.datum <= b.datum;
+}
+
+static __inline__ void dn_rebuild_zone(struct dn_zone *dz,
+					struct dn_fib_node **old_ht,
+					int old_divisor)
+{
+	int i;
+	struct dn_fib_node *f, **fp, *next;
+
+	for(i = 0; i < old_divisor; i++) {
+		for(f = old_ht[i]; f; f = f->fn_next) {
+			next = f->fn_next;
+			for(fp = dn_chain_p(f->fn_key, dz);
+				*fp && dn_key_leq((*fp)->fn_key, f->fn_key);
+				fp = &(*fp)->fn_next)
+				/* NOTHING */;
+			f->fn_next = *fp;
+			*fp = f;
+		}
+	}
+}
+
+static void dn_rehash_zone(struct dn_zone *dz)
+{
+	struct dn_fib_node **ht, **old_ht;
+	int old_divisor, new_divisor;
+	u32 new_hashmask;
+
+	old_divisor = dz->dz_divisor;
+
+	switch(old_divisor) {
+		case 16:
+			new_divisor = 256;
+			new_hashmask = 0xFF;
+			break;
+		default:
+			printk(KERN_DEBUG "DECnet: dn_rehash_zone: BUG! %d\n", old_divisor);
+		case 256:
+			new_divisor = 1024;
+			new_hashmask = 0x3FF;
+			break;
+	}
+
+	ht = kmalloc(new_divisor*sizeof(struct dn_fib_node*), GFP_KERNEL);
+
+	if (ht == NULL)
+		return;
+
+	memset(ht, 0, new_divisor*sizeof(struct dn_fib_node *));
+	write_lock_bh(&dn_fib_tables_lock);
+	old_ht = dz->dz_hash;
+	dz->dz_hash = ht;
+	dz->dz_hashmask = new_hashmask;
+	dz->dz_divisor = new_divisor;
+	dn_rebuild_zone(dz, old_ht, old_divisor);
+	write_unlock_bh(&dn_fib_tables_lock);
+	kfree(old_ht);
+}
+
+static void dn_free_node(struct dn_fib_node *f)
+{
+	dn_fib_release_info(DN_FIB_INFO(f));
+	kmem_cache_free(dn_hash_kmem, f);
+}
+
+
+static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
+{
+	int i;
+	struct dn_zone *dz = kmalloc(sizeof(struct dn_zone), GFP_KERNEL);
+	if (!dz)
+		return NULL;
+
+	memset(dz, 0, sizeof(struct dn_zone));
+	if (z) {
+		dz->dz_divisor = 16;
+		dz->dz_hashmask = 0x0F;
+	} else {
+		dz->dz_divisor = 1;
+		dz->dz_hashmask = 0;
+	}
+
+	dz->dz_hash = kmalloc(dz->dz_divisor*sizeof(struct dn_fib_node *), GFP_KERNEL);
+
+	if (!dz->dz_hash) {
+		kfree(dz);
+		return NULL;
+	}
+
+	memset(dz->dz_hash, 0, dz->dz_divisor*sizeof(struct dn_fib_node*));
+	dz->dz_order = z;
+	dz->dz_mask = dnet_make_mask(z);
+
+	for(i = z + 1; i <= 16; i++)
+		if (table->dh_zones[i])
+			break;
+
+	write_lock_bh(&dn_fib_tables_lock);
+	if (i>16) {
+		dz->dz_next = table->dh_zone_list;
+		table->dh_zone_list = dz;
+	} else {
+		dz->dz_next = table->dh_zones[i]->dz_next;
+		table->dh_zones[i]->dz_next = dz;
+	}
+	table->dh_zones[z] = dz;
+	write_unlock_bh(&dn_fib_tables_lock);
+	return dz;
+}
+
+
+static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi)
+{
+	struct rtnexthop *nhp;
+	int nhlen;
+
+	if (rta->rta_priority && *rta->rta_priority != fi->fib_priority)
+		return 1;
+
+	if (rta->rta_oif || rta->rta_gw) {
+		if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
+		    (!rta->rta_gw  || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0))
+			return 0;
+		return 1;
+	}
+
+	if (rta->rta_mp == NULL)
+		return 0;
+
+	nhp = RTA_DATA(rta->rta_mp);
+	nhlen = RTA_PAYLOAD(rta->rta_mp);
+
+	for_nexthops(fi) {
+		int attrlen = nhlen - sizeof(struct rtnexthop);
+		dn_address gw;
+
+		if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)
+			return -EINVAL;
+		if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
+			return 1;
+		if (attrlen) {
+			gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+
+			if (gw && gw != nh->nh_gw)
+				return 1;
+		}
+		nhp = RTNH_NEXT(nhp);
+	} endfor_nexthops(fi);
+
+	return 0;
+}
+
+#ifdef CONFIG_RTNETLINK
+static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
+                        u8 tb_id, u8 type, u8 scope, void *dst, int dst_len,
+                        struct dn_fib_info *fi)
+{
+        struct rtmsg *rtm;
+        struct nlmsghdr *nlh;
+        unsigned char *b = skb->tail;
+
+        nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm));
+        rtm = NLMSG_DATA(nlh);
+        rtm->rtm_family = AF_DECnet;
+        rtm->rtm_dst_len = dst_len;
+        rtm->rtm_src_len = 0;
+        rtm->rtm_tos = 0;
+        rtm->rtm_table = tb_id;
+        rtm->rtm_flags = fi->fib_flags;
+        rtm->rtm_scope = scope;
+	rtm->rtm_type  = type;
+        if (rtm->rtm_dst_len)
+                RTA_PUT(skb, RTA_DST, 2, dst);
+        rtm->rtm_protocol = fi->fib_protocol;
+        if (fi->fib_priority)
+                RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
+        if (fi->fib_nhs == 1) {
+                if (fi->fib_nh->nh_gw)
+                        RTA_PUT(skb, RTA_GATEWAY, 2, &fi->fib_nh->nh_gw);
+                if (fi->fib_nh->nh_oif)
+                        RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif);
+        }
+        if (fi->fib_nhs > 1) {
+                struct rtnexthop *nhp;
+                struct rtattr *mp_head;
+                if (skb_tailroom(skb) <= RTA_SPACE(0))
+                        goto rtattr_failure;
+                mp_head = (struct rtattr *)skb_put(skb, RTA_SPACE(0));
+
+                for_nexthops(fi) {
+                        if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
+                                goto rtattr_failure;
+                        nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
+                        nhp->rtnh_flags = nh->nh_flags & 0xFF;
+                        nhp->rtnh_hops = nh->nh_weight - 1;
+                        nhp->rtnh_ifindex = nh->nh_oif;
+                        if (nh->nh_gw)
+                                RTA_PUT(skb, RTA_GATEWAY, 2, &nh->nh_gw);
+                        nhp->rtnh_len = skb->tail - (unsigned char *)nhp;
+                } endfor_nexthops(fi);
+                mp_head->rta_type = RTA_MULTIPATH;
+                mp_head->rta_len = skb->tail - (u8*)mp_head;
+        }
+
+        nlh->nlmsg_len = skb->tail - b;
+        return skb->len;
+
+
+nlmsg_failure:
+rtattr_failure:
+        skb_trim(skb, b - skb->data);
+        return -1;
+}
+
+
+static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id,
+                        struct nlmsghdr *nlh, struct netlink_skb_parms *req)
+{
+        struct sk_buff *skb;
+        u32 pid = req ? req->pid : 0;
+        int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256);
+
+        skb = alloc_skb(size, GFP_KERNEL);
+        if (!skb)
+                return;
+
+        if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, 
+                                f->fn_type, f->fn_scope, &f->fn_key, z, 
+                                DN_FIB_INFO(f)) < 0) {
+                kfree_skb(skb);
+                return;
+        }
+        NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_ROUTE;
+        if (nlh->nlmsg_flags & NLM_F_ECHO)
+                atomic_inc(&skb->users);
+        netlink_broadcast(rtnl, skb, pid, RTMGRP_DECnet_ROUTE, GFP_KERNEL);
+        if (nlh->nlmsg_flags & NLM_F_ECHO)
+                netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
+}
+
+static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, 
+				struct netlink_callback *cb,
+				struct dn_fib_table *tb,
+				struct dn_zone *dz,
+				struct dn_fib_node *f)
+{
+	int i, s_i;
+
+	s_i = cb->args[3];
+	for(i = 0; f; i++, f = f->fn_next) {
+		if (i < s_i)
+			continue;
+		if (f->fn_state & DN_S_ZOMBIE)
+			continue;
+		if (dn_fib_dump_info(skb, NETLINK_CB(cb->skb).pid, 
+				cb->nlh->nlmsg_seq,
+				RTM_NEWROUTE,
+				tb->n, 
+				(f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
+				f->fn_scope, &f->fn_key, dz->dz_order, 
+				f->fn_info) < 0) {
+			cb->args[3] = i;
+			return -1;
+		}
+	}
+	cb->args[3] = i;
+	return skb->len;
+}
+
+static __inline__ int dn_hash_dump_zone(struct sk_buff *skb, 
+				struct netlink_callback *cb,
+				struct dn_fib_table *tb,
+				struct dn_zone *dz)
+{
+	int h, s_h;
+
+	s_h = cb->args[2];
+	for(h = 0; h < dz->dz_divisor; h++) {
+		if (h < s_h)
+			continue;
+		if (h > s_h)
+			memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
+		if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
+			continue;
+		if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
+			cb->args[2] = h;
+			return -1;
+		}
+	}
+	cb->args[2] = h;
+	return skb->len;
+}
+
+static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, 
+                                struct netlink_callback *cb)
+{
+        int m, s_m;
+	struct dn_zone *dz;
+	struct dn_hash *table = (struct dn_hash *)tb->data;
+
+	s_m = cb->args[1];
+	read_lock(&dn_fib_tables_lock);
+	for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
+		if (m < s_m)
+			continue;
+		if (m > s_m)
+			memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
+
+		if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
+			cb->args[1] = m;
+			read_unlock(&dn_fib_tables_lock);
+			return -1;
+		}
+	}
+	read_unlock(&dn_fib_tables_lock);
+	cb->args[1] = m;
+
+        return skb->len;
+}
+
+#else /* no CONFIG_RTNETLINK */
+
+#define dn_rt_msg_fib(event,f,z,tb_id,nlh,req)
+
+#endif /* CONFIG_RTNETLINK */
+
+static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
+{
+	struct dn_hash *table = (struct dn_hash *)tb->data;
+	struct dn_fib_node *new_f, *f, **fp, **del_fp;
+	struct dn_zone *dz;
+	struct dn_fib_info *fi;
+        int z = r->rtm_dst_len;
+	int type = r->rtm_type;
+	dn_fib_key_t key;
+        int err;
+
+        if (z > 16)
+                return -EINVAL;
+
+	dz = table->dh_zones[z];
+	if (!dz && !(dz = dn_new_zone(table, z)))
+		return -ENOBUFS;
+
+	dz_key_0(key);
+	if (rta->rta_dst) {
+		dn_address dst;
+		memcpy(&dst, rta->rta_dst, 2);
+		if (dst & ~DZ_MASK(dz))
+			return -EINVAL;
+		key = dz_key(dst, dz);
+	}
+
+        if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL)
+                return err;
+
+	if (dz->dz_nent > (dz->dz_divisor << 2) &&
+			dz->dz_divisor > DN_MAX_DIVISOR &&
+			(z==16 || (1<<z) > dz->dz_divisor))
+		dn_rehash_zone(dz);
+
+	fp = dn_chain_p(key, dz);
+
+	DN_FIB_SCAN(f, fp) {
+		if (dn_key_leq(key, f->fn_key))
+			break;
+	}
+
+	del_fp = NULL;
+
+	if (f && (f->fn_state & DN_S_ZOMBIE) &&
+			dn_key_eq(f->fn_key, key)) {
+		del_fp = fp;
+		fp = &f->fn_next;
+		f = *fp;
+		goto create;
+	}
+
+	DN_FIB_SCAN_KEY(f, fp, key) {
+		if (fi->fib_priority <= DN_FIB_INFO(f)->fib_priority)
+			break;
+	}
+
+	if (f && dn_key_eq(f->fn_key, key) &&
+			fi->fib_priority == DN_FIB_INFO(f)->fib_priority) {
+		struct dn_fib_node **ins_fp;
+
+		err = -EEXIST;
+		if (n->nlmsg_flags & NLM_F_EXCL)
+			goto out;
+
+		if (n->nlmsg_flags & NLM_F_REPLACE) {
+			del_fp = fp;
+			fp = &f->fn_next;
+			f = *fp;
+			goto replace;
+		}
+
+		ins_fp = fp;
+		err = -EEXIST;
+
+		DN_FIB_SCAN_KEY(f, fp, key) {
+			if (fi->fib_priority != DN_FIB_INFO(f)->fib_priority)
+				break;
+			if (f->fn_type == type && f->fn_scope == r->rtm_scope
+					&& DN_FIB_INFO(f) == fi)
+				goto out;
+		}
+
+		if (!(n->nlmsg_flags & NLM_F_APPEND)) {
+			fp = ins_fp;
+			f = *fp;
+		}
+	}
+
+create:
+	err = -ENOENT;
+	if (!(n->nlmsg_flags & NLM_F_CREATE))
+		goto out;
+
+replace:
+	err = -ENOBUFS;
+	new_f = kmem_cache_alloc(dn_hash_kmem, SLAB_KERNEL);
+	if (new_f == NULL)
+		goto out;
+
+	memset(new_f, 0, sizeof(struct dn_fib_node));
+
+	new_f->fn_key = key;
+	new_f->fn_type = type;
+	new_f->fn_scope = r->rtm_scope;
+	DN_FIB_INFO(new_f) = fi;
+
+	new_f->fn_next = f;
+	write_lock_bh(&dn_fib_tables_lock);
+	*fp = new_f;
+	write_unlock_bh(&dn_fib_tables_lock);
+	dz->dz_nent++;
+
+	if (del_fp) {
+		f = *del_fp;
+		write_lock_bh(&dn_fib_tables_lock);
+		*del_fp = f->fn_next;
+		write_unlock_bh(&dn_fib_tables_lock);
+
+		if (!(f->fn_state & DN_S_ZOMBIE))
+			dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
+		if (f->fn_state & DN_S_ACCESSED)
+			dn_rt_cache_flush(-1);
+		dn_free_node(f);
+		dz->dz_nent--;
+	} else {
+		dn_rt_cache_flush(-1);
+	}
+
+        dn_rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->n, n, req);
+
+        return 0;
+out:
+	dn_fib_release_info(fi);
+	return err;
+}
+
+
+static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
+{
+	struct dn_hash *table = (struct dn_hash*)tb->data;
+	struct dn_fib_node **fp, **del_fp, *f;
+        int z = r->rtm_dst_len;
+	struct dn_zone *dz;
+	dn_fib_key_t key;
+	int matched;
+
+
+        if (z > 16)
+                return -EINVAL;
+
+	if ((dz = table->dh_zones[z]) == NULL)
+		return -ESRCH;
+
+	dz_key_0(key);
+	if (rta->rta_dst) {
+		dn_address dst;
+		memcpy(&dst, rta->rta_dst, 2);
+		if (dst & ~DZ_MASK(dz))
+			return -EINVAL;
+		key = dz_key(dst, dz);
+	}
+
+	fp = dn_chain_p(key, dz);
+
+	DN_FIB_SCAN(f, fp) {
+		if (dn_key_eq(f->fn_key, key))
+			break;
+		if (dn_key_leq(key, f->fn_key))
+			return -ESRCH;
+	}
+
+	matched = 0;
+	del_fp = NULL;
+	DN_FIB_SCAN_KEY(f, fp, key) {
+		struct dn_fib_info *fi = DN_FIB_INFO(f);
+
+		if (f->fn_state & DN_S_ZOMBIE)
+			return -ESRCH;
+
+		matched++;
+
+		if (del_fp == NULL &&
+				(!r->rtm_type || f->fn_type == r->rtm_type) &&
+				(r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
+				(!r->rtm_protocol || 
+					fi->fib_protocol == r->rtm_protocol) &&
+				dn_fib_nh_match(r, n, rta, fi) == 0)
+			del_fp = fp;
+	}
+
+	if (del_fp) {
+		f = *del_fp;
+        	dn_rtmsg_fib(RTM_DELROUTE, f, z, tb->n, n, req);
+
+		if (matched != 1) {
+			write_lock_bh(&dn_fib_tables_lock);
+			*del_fp = f->fn_next;
+			write_unlock_bh(&dn_fib_tables_lock);
+
+			if (f->fn_state & DN_S_ACCESSED)
+				dn_rt_cache_flush(-1);
+			dn_free_node(f);
+			dz->dz_nent--;
+		} else {
+			f->fn_state |= DN_S_ZOMBIE;
+			if (f->fn_state & DN_S_ACCESSED) {
+				f->fn_state &= ~DN_S_ACCESSED;
+				dn_rt_cache_flush(-1);
+			}
+			if (++dn_fib_hash_zombies > 128)
+				dn_fib_flush();
+		}
+
+		return 0;
+	}
+
+        return -ESRCH;
+}
+
+static __inline__ int dn_flush_list(struct dn_fib_node **fp, int z, struct dn_hash *table)
+{
+	int found = 0;
+	struct dn_fib_node *f;
+
+	while((f = *fp) != NULL) {
+		struct dn_fib_info *fi = DN_FIB_INFO(f);
+
+		if (fi && ((f->fn_state & DN_S_ZOMBIE) || (fi->fib_flags & RTNH_F_DEAD))) {
+			write_lock_bh(&dn_fib_tables_lock);
+			*fp = f->fn_next;
+			write_unlock_bh(&dn_fib_tables_lock);
+
+			dn_free_node(f);
+			found++;
+			continue;
+		}
+		fp = &f->fn_next;
+	}
+
+	return found;
+}
+
+static int dn_fib_table_flush(struct dn_fib_table *tb)
+{
+	struct dn_hash *table = (struct dn_hash *)tb->data;
+	struct dn_zone *dz;
+	int found = 0;
+
+	dn_fib_hash_zombies = 0;
+	for(dz = table->dh_zone_list; dz; dz = dz->dz_next) {
+		int i;
+		int tmp = 0;
+		for(i = dz->dz_divisor-1; i >= 0; i--)
+			tmp += dn_flush_list(&dz->dz_hash[i], dz->dz_order, table);
+		dz->dz_nent -= tmp;
+		found += tmp;
+	}
+
+	return found;
+}
+
+static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct dn_fib_key *
+key, struct dn_fib_res *res)
+{
+        int err;
+	struct dn_zone *dz;
+	struct dn_hash *t = (struct dn_hash *)tb->data;
+
+	read_lock(&dn_fib_tables_lock);
+	for(dz = t->dh_zone_list; dz; dz = dz->dz_next) {
+		struct dn_fib_node *f;
+		dn_fib_key_t k = dz_key(key->dst, dz);
+
+		for(f = dz_chain(k, dz); f; f = f->fn_next) {
+			if (!dn_key_leq(k, f->fn_key))
+				break;
+			else
+				continue;
+
+			f->fn_state |= DN_S_ACCESSED;
+
+			if (f->fn_state&DN_S_ZOMBIE)
+				continue;
+			if (f->fn_scope < key->scope)
+				continue;
+
+			err = dn_fib_semantic_match(f->fn_type, DN_FIB_INFO(f), key, res);
+			if (err == 0) {
+				res->type = f->fn_type;
+				res->scope = f->fn_scope;
+				res->prefixlen = dz->dz_order;
+				goto out;
+			}
+			if (err < 0)
+				goto out;
+		}
+	}
+	err = 1;
+out:
+	read_unlock(&dn_fib_tables_lock);
+        return err;
+}
+
+#ifdef CONFIG_PROC_FS
+
+static unsigned dn_fib_flag_trans(int type, int dead, u16 mask, struct dn_fib_info *fi)
+{
+	static unsigned type2flags[RTN_MAX+1] = {
+		0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0
+	};
+	unsigned flags = type2flags[type];
+
+	if (fi && fi->fib_nh->nh_gw)
+		flags |= RTF_GATEWAY;
+	if (mask == 0xFFFF)
+		flags |= RTF_HOST;
+	if (dead)
+		flags |= RTF_UP;
+	return flags;
+}
+
+static void dn_fib_node_get_info(int type, int dead, struct dn_fib_info *fi, u16 prefix, u16 mask, char *buffer)
+{
+	int len;
+	unsigned flags = dn_fib_flag_trans(type, dead, mask, fi);
+
+	if (fi) {
+		len = sprintf(buffer, "%s\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u",
+				fi->fib_dev ? fi->fib_dev->name : "*", prefix,
+				fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
+				mask, 0, 0, 0);
+	} else {
+		len = sprintf(buffer, "*\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u",
+					prefix, 0,
+					flags, 0, 0, 0,
+					mask, 0, 0, 0);
+	}
+	memset(buffer+len, ' ', 127-len);
+	buffer[127] = '\n';
+}
+
+static int dn_fib_table_get_info(struct dn_fib_table *tb, char *buffer, int first, int count)
+{
+	struct dn_hash *table = (struct dn_hash *)tb->data;
+	struct dn_zone *dz;
+	int pos = 0;
+	int n = 0;
+
+	read_lock(&dn_fib_tables_lock);
+	for(dz = table->dh_zone_list; dz; dz = dz->dz_next) {
+		int i;
+		struct dn_fib_node *f;
+		int maxslot = dz->dz_divisor;
+		struct dn_fib_node **fp = dz->dz_hash;
+
+		if (dz->dz_nent == 0)
+			continue;
+
+		if (pos + dz->dz_nent < first) {
+			pos += dz->dz_nent;
+			continue;
+		}
+
+		for(i = 0; i < maxslot; i++, fp++) {
+			for(f = *fp; f ; f = f->fn_next) {
+				if (++pos <= first)
+					continue;
+				dn_fib_node_get_info(f->fn_type,
+						f->fn_state & DN_S_ZOMBIE,
+						DN_FIB_INFO(f),
+						dz_prefix(f->fn_key, dz),
+						DZ_MASK(dz), buffer);
+				buffer += 128;
+				if (++n >= count)
+					goto out;
+			}
+		}
+	}
+out:
+	read_unlock(&dn_fib_tables_lock);
+	return n;
+}
+#endif /* CONFIG_PROC_FS */
+
+struct dn_fib_table *dn_fib_get_table(int n, int create)
+{
+        struct dn_fib_table *t;
+
+        if (n < DN_MIN_TABLE)
+                return NULL;
+
+        if (n > DN_NUM_TABLES)
+                return NULL;
+
+        if (dn_fib_tables[n]) 
+                return dn_fib_tables[n];
+
+        if (!create)
+                return NULL;
+
+        if (in_interrupt() && net_ratelimit()) {
+                printk(KERN_DEBUG "DECnet: BUG! Attempt to create routing table 
+from interrupt\n"); 
+                return NULL;
+        }
+        if ((t = kmalloc(sizeof(struct dn_fib_table), GFP_KERNEL)) == NULL)
+                return NULL;
+
+        memset(t, 0, sizeof(struct dn_fib_table));
+
+        t->n = n;
+        t->insert = dn_fib_table_insert;
+        t->delete = dn_fib_table_delete;
+        t->lookup = dn_fib_table_lookup;
+        t->flush  = dn_fib_table_flush;
+#ifdef CONFIG_PROC_FS
+	t->get_info = dn_fib_table_get_info;
+#endif
+#ifdef CONFIG_RTNETLINK
+        t->dump = dn_fib_table_dump;
+#endif
+        dn_fib_tables[n] = t;
+
+        return t;
+}
+
+static void dn_fib_del_tree(int n)
+{
+        struct dn_fib_table *t;
+
+        write_lock(&dn_fib_tables_lock);
+        t = dn_fib_tables[n];
+        dn_fib_tables[n] = NULL;
+        write_unlock(&dn_fib_tables_lock);
+
+        if (t) {
+                kfree_s(t, sizeof(struct dn_fib_table));
+        }
+}
+
+struct dn_fib_table *dn_fib_empty_table(void)
+{
+        int id;
+
+        for(id = DN_MIN_TABLE; id <= DN_NUM_TABLES; id++)
+                if (dn_fib_tables[id] == NULL)
+                        return dn_fib_get_table(id, 1);
+        return NULL;
+}
+
+void __init dn_fib_table_init(void)
+{
+	dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
+					sizeof(struct dn_fib_info),
+					0, SLAB_HWCACHE_ALIGN,
+					NULL, NULL);
+}
+
+void __exit dn_fib_table_cleanup(void)
+{
+	return;
+}
+
diff -u --recursive --new-file v2.3.38/linux/net/decnet/sysctl_net_decnet.c linux/net/decnet/sysctl_net_decnet.c
--- v2.3.38/linux/net/decnet/sysctl_net_decnet.c	Tue Dec 14 01:27:24 1999
+++ linux/net/decnet/sysctl_net_decnet.c	Sat Jan  8 21:36:20 2000
@@ -104,123 +104,6 @@
 	return 0;
 }
 
-static char *node2str(int n)
-{
-	switch(n) {
-		case DN_RT_INFO_ENDN:
-			return "EndNode\n";
-		case DN_RT_INFO_L1RT:
-			return "Level 1 Router\n";
-		case DN_RT_INFO_L2RT:
-			return "Level 2 Router\n";
-	}
-
-	return "Unknown\n";
-}
-
-static int dn_node_type_strategy(ctl_table *table, int *name, int nlen,
-				void *oldval, size_t *oldlenp,
-				void *newval, size_t newlen,
-				void **context)
-{
-	int len;
-	int type;
-
-	if (oldval && oldlenp) {
-		if (get_user(len, oldlenp))
-			return -EFAULT;
-		if (len) {
-			if (len != sizeof(int))
-				return -EINVAL;
-			if (put_user(decnet_node_type, (int *)oldval))
-				return -EFAULT;
-		}
-	}
-
-	if (newval && newlen) {
-		if (newlen != sizeof(int))
-			return -EINVAL;
-
-		if (get_user(type, (int *)newval))
-			return -EFAULT;
-
-		switch(type) {
-			case DN_RT_INFO_ENDN: /* EndNode        */
-#ifdef CONFIG_DECNET_ROUTER
-			case DN_RT_INFO_L1RT: /* Level 1 Router */
-			case DN_RT_INFO_L2RT: /* Level 2 Router */
-#endif
-				break;
-			default:
-				return -EINVAL;
-		}
-
-		if (decnet_node_type != type) {
-			dn_dev_devices_off();
-			decnet_node_type = type;
-			dn_dev_devices_on();
-		}
-	}
-	return 0;
-}
-
-static int dn_node_type_handler(ctl_table *table, int write, 
-				struct file * filp,
-				void *buffer, size_t *lenp)
-{
-	char *s = node2str(decnet_node_type);
-	int len = strlen(s);
-
-	if (!*lenp || (filp->f_pos && !write)) {
-		*lenp = 0;
-		return 0;
-	}
-
-	if (write) {
-		char c = *(char *)buffer;
-		int type = 0;
-
-		switch(c) {
-			case 'e':
-			case 'E':
-			case '0':
-				type = DN_RT_INFO_ENDN;
-				break;
-#ifdef CONFIG_DECNET_ROUTER
-			case 'r':
-			case '1':
-				type = DN_RT_INFO_L1RT;
-				break;
-			case 'R':
-			case '2':
-				type = DN_RT_INFO_L2RT;
-				break;
-#endif /* CONFIG_DECNET_ROUTER */
-			default:
-				return -EINVAL;	
-		}
-
-		if (decnet_node_type != type) {
-			dn_dev_devices_off();
-			decnet_node_type = type;
-			dn_dev_devices_on();
-		}
-
-		filp->f_pos += 1;
-
-		return 0;
-	}
-
-	if (len > *lenp) len = *lenp;
-
-	if (copy_to_user(buffer, s, len))
-		return -EFAULT;
-
-	*lenp = len;
-	filp->f_pos += len;
-
-	return 0;
-}
 
 static int dn_node_address_strategy(ctl_table *table, int *name, int nlen,
 				void *oldval, size_t *oldlenp,
@@ -374,6 +257,7 @@
 	}
 
 	if (write) {
+		int i;
 
 		if (*lenp > 16)
 			return -E2BIG;
@@ -382,6 +266,9 @@
 			return -EFAULT;
 
 		devname[*lenp] = 0;
+		for(i = 0; i < (*lenp); i++)
+			if (devname[i] == '\n')
+				devname[i] = 0;
 
 		if ((dev = __dev_get_by_name(devname)) == NULL)
 			return -ENODEV;
@@ -416,9 +303,6 @@
 }
 
 static ctl_table dn_table[] = {
-	{NET_DECNET_NODE_TYPE, "node_type", NULL, 1, 0644, NULL,
-	dn_node_type_handler, dn_node_type_strategy, NULL,
-	NULL, NULL},
 	{NET_DECNET_NODE_ADDRESS, "node_address", NULL, 7, 0644, NULL,
 	dn_node_address_handler, dn_node_address_strategy, NULL,
 	NULL, NULL},
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.38/linux/net/ipv4/af_inet.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/af_inet.c	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.100 1999/12/21 04:05:02 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.101 2000/01/09 02:19:38 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -115,7 +115,7 @@
 
 #define min(a,b)	((a)<(b)?(a):(b))
 
-struct linux_mib net_statistics;
+struct linux_mib net_statistics[NR_CPUS*2];
 
 atomic_t inet_sock_nr;
 
@@ -397,7 +397,7 @@
 	sk->timer.data = (unsigned long)sk;
 	sk->timer.function = &tcp_keepalive_timer;
 
-	sk->protinfo.af_inet.ttl=ip_statistics.IpDefaultTTL;
+	sk->protinfo.af_inet.ttl=sysctl_ip_default_ttl;
 
 	sk->protinfo.af_inet.mc_loop=1;
 	sk->protinfo.af_inet.mc_ttl=1;
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.3.38/linux/net/ipv4/devinet.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/devinet.c	Sat Jan  8 21:36:20 2000
@@ -1,7 +1,7 @@
 /*
  *	NET3	IP device support routines.
  *
- *	Version: $Id: devinet.c,v 1.35 1999/08/31 07:03:20 davem Exp $
+ *	Version: $Id: devinet.c,v 1.36 2000/01/09 02:19:46 davem Exp $
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -730,7 +730,7 @@
 	read_unlock(&in_dev->lock);
 	read_unlock(&inetdev_lock);
 
-	if (addr || scope >= RT_SCOPE_LINK)
+	if (addr)
 		return addr;
 
 	/* Not loopback addresses on loopback should be preferred
@@ -745,7 +745,8 @@
 
 		read_lock(&in_dev->lock);
 		for_primary_ifa(in_dev) {
-			if (ifa->ifa_scope <= scope) {
+			if (ifa->ifa_scope != RT_SCOPE_LINK &&
+			    ifa->ifa_scope <= scope) {
 				read_unlock(&in_dev->lock);
 				read_unlock(&inetdev_lock);
 				read_unlock(&dev_base_lock);
@@ -1001,8 +1002,6 @@
 	read_unlock(&dev_base_lock);
 
 	rt_cache_flush(0);
-
-	ip_statistics.IpForwarding = on ? 1 : 2;
 }
 
 static
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.3.38/linux/net/ipv4/icmp.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/icmp.c	Sat Jan  8 21:36:20 2000
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.62 1999/12/23 01:43:37 davem Exp $
+ *	Version: $Id: icmp.c,v 1.63 2000/01/09 02:19:45 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -285,7 +285,7 @@
  *	Statistics
  */
  
-struct icmp_mib icmp_statistics;
+struct icmp_mib icmp_statistics[NR_CPUS*2];
 
 /* An array of errno for error messages from dest unreach. */
 /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOS_UNREACH and SR_FAIELD MUST be considered 'transient errs'. */
@@ -468,8 +468,8 @@
 {
 	if (type>NR_ICMP_TYPES)
 		return;
-	(*icmp_pointers[type].output)++;
-	icmp_statistics.IcmpOutMsgs++;
+	(icmp_pointers[type].output)[(smp_processor_id()*2+!in_interrupt())*sizeof(struct icmp_mib)/sizeof(unsigned long)]++;
+	ICMP_INC_STATS(IcmpOutMsgs);
 }
  
 /*
@@ -527,9 +527,12 @@
 
 	sk->protinfo.af_inet.tos = skb->nh.iph->tos;
 	daddr = ipc.addr = rt->rt_src;
-	ipc.opt = &icmp_param->replyopts;
-	if (ipc.opt->srr)
-		daddr = icmp_param->replyopts.faddr;
+	ipc.opt = NULL;
+	if (icmp_param->replyopts.optlen) {
+		ipc.opt = &icmp_param->replyopts;
+		if (ipc.opt->srr)
+			daddr = icmp_param->replyopts.faddr;
+	}
 	if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
 		goto out;
 	ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
@@ -561,49 +564,41 @@
 	struct ipcm_cookie ipc;
 	u32 saddr;
 	u8  tos;
-	
+
+	if (!rt)
+		return;
+
 	/*
 	 *	Find the original header
 	 */
-	 
 	iph = skb_in->nh.iph;
-	
+
 	/*
 	 *	No replies to physical multicast/broadcast
 	 */
-	 
 	if (skb_in->pkt_type!=PACKET_HOST)
 		return;
-		
+
 	/*
 	 *	Now check at the protocol level
 	 */
-	if (!rt) {
-		if (net_ratelimit())
-			printk(KERN_DEBUG "icmp_send: destinationless packet\n");
-		return;
-	}
 	if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
 		return;
-	 
-		
+
 	/*
 	 *	Only reply to fragment 0. We byte re-order the constant
 	 *	mask for efficiency.
 	 */
-	 
 	if (iph->frag_off&htons(IP_OFFSET))
 		return;
-		
+
 	/* 
 	 *	If we send an ICMP error to an ICMP error a mess would result..
 	 */
-	 
 	if (icmp_pointers[type].error) {
 		/*
 		 *	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));
 			/*
@@ -649,7 +644,7 @@
 	 */
 	if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
 		goto out;
-	
+
 	if (ip_options_echo(&icmp_param.replyopts, skb_in)) 
 		goto ende;
 
@@ -719,7 +714,7 @@
 	 */
 
 	if(len<sizeof(struct iphdr)) {
-		icmp_statistics.IcmpInErrors++;
+		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
 		
@@ -841,7 +836,7 @@
 	unsigned long ip;
 
 	if (len < sizeof(struct iphdr)) {
-		icmp_statistics.IcmpInErrors++;
+		ICMP_INC_STATS_BH(IcmpInErrors);
 		return; 
 	}
 		
@@ -910,7 +905,7 @@
 	 */
 	 
 	if(len<12) {
-		icmp_statistics.IcmpInErrors++;
+		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
 	
@@ -1024,7 +1019,7 @@
 	struct icmphdr *icmph = skb->h.icmph;
 	struct rtable *rt = (struct rtable*)skb->dst;
 
-	icmp_statistics.IcmpInMsgs++;
+	ICMP_INC_STATS_BH(IcmpInMsgs);
 
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
@@ -1060,14 +1055,14 @@
 	}
 
 	len -= sizeof(struct icmphdr);
-	(*icmp_pointers[icmph->type].input)++;
+	icmp_pointers[icmph->type].input[smp_processor_id()*2*sizeof(struct icmp_mib)/sizeof(unsigned long)]++;
 	(icmp_pointers[icmph->type].handler)(icmph, skb, len);
 
 drop:
 	kfree_skb(skb);
 	return 0;
 error:
-	icmp_statistics.IcmpInErrors++;
+	ICMP_INC_STATS_BH(IcmpInErrors);
 	goto drop;
 }
 
@@ -1096,37 +1091,37 @@
  
 static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
 /* ECHO REPLY (0) */
- { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, &sysctl_icmp_echoreply_time},
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+ { &icmp_statistics[0].IcmpOutEchoReps, &icmp_statistics[0].IcmpInEchoReps, icmp_discard, 0, &sysctl_icmp_echoreply_time},
+ { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
+ { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
 /* DEST UNREACH (3) */
- { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time },
+ { &icmp_statistics[0].IcmpOutDestUnreachs, &icmp_statistics[0].IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time },
 /* SOURCE QUENCH (4) */
- { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, },
+ { &icmp_statistics[0].IcmpOutSrcQuenchs, &icmp_statistics[0].IcmpInSrcQuenchs, icmp_unreach, 1, },
 /* REDIRECT (5) */
- { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+ { &icmp_statistics[0].IcmpOutRedirects, &icmp_statistics[0].IcmpInRedirects, icmp_redirect, 1, },
+ { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
+ { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
 /* ECHO (8) */
- { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0, },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
- { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, },
+ { &icmp_statistics[0].IcmpOutEchos, &icmp_statistics[0].IcmpInEchos, icmp_echo, 0, },
+ { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
+ { &dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
 /* TIME EXCEEDED (11) */
- { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1, &sysctl_icmp_timeexceed_time },
+ { &icmp_statistics[0].IcmpOutTimeExcds, &icmp_statistics[0].IcmpInTimeExcds, icmp_unreach, 1, &sysctl_icmp_timeexceed_time },
 /* PARAMETER PROBLEM (12) */
- { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_unreach, 1, &sysctl_icmp_paramprob_time },
+ { &icmp_statistics[0].IcmpOutParmProbs, &icmp_statistics[0].IcmpInParmProbs, icmp_unreach, 1, &sysctl_icmp_paramprob_time },
 /* TIMESTAMP (13) */
- { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0,  },
+ { &icmp_statistics[0].IcmpOutTimestamps, &icmp_statistics[0].IcmpInTimestamps, icmp_timestamp, 0,  },
 /* TIMESTAMP REPLY (14) */
- { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0, },
+ { &icmp_statistics[0].IcmpOutTimestampReps, &icmp_statistics[0].IcmpInTimestampReps, icmp_discard, 0, },
 /* INFO (15) */
  { &dummy, &dummy, icmp_discard, 0, },
 /* INFO REPLY (16) */
  { &dummy, &dummy, icmp_discard, 0, },
 /* ADDR MASK (17) */
- { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0,  },
+ { &icmp_statistics[0].IcmpOutAddrMasks, &icmp_statistics[0].IcmpInAddrMasks, icmp_address, 0,  },
 /* ADDR MASK REPLY (18) */
- { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_address_reply, 0, }
+ { &icmp_statistics[0].IcmpOutAddrMaskReps, &icmp_statistics[0].IcmpInAddrMaskReps, icmp_address_reply, 0, }
 };
 
 void __init icmp_init(struct net_proto_family *ops)
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.3.38/linux/net/ipv4/ip_forward.c	Thu Aug 26 13:05:45 1999
+++ linux/net/ipv4/ip_forward.c	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
  *
  *		The IP forwarding functionality.
  *		
- * Version:	$Id: ip_forward.c,v 1.45 1999/08/20 11:05:16 davem Exp $
+ * Version:	$Id: ip_forward.c,v 1.46 2000/01/09 02:19:37 davem Exp $
  *
  * Authors:	see ip.c
  *
@@ -45,7 +45,7 @@
 {
 	struct ip_options * opt	= &(IPCB(skb)->opt);
 
-	ip_statistics.IpForwDatagrams++;
+	IP_INC_STATS_BH(IpForwDatagrams);
 
 	if (opt->optlen == 0) {
 #ifdef CONFIG_NET_FASTROUTE
@@ -147,7 +147,7 @@
 		       ip_forward_finish);
 
 frag_needed:
-	ip_statistics.IpFragFails++;
+	IP_INC_STATS_BH(IpFragFails);
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
         goto drop;
 
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.3.38/linux/net/ipv4/ip_fragment.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/ip_fragment.c	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.45 1999/08/30 10:17:10 davem Exp $
+ * Version:	$Id: ip_fragment.c,v 1.46 2000/01/09 02:19:36 davem Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -211,8 +211,8 @@
   	}
   
 	/* Send an ICMP "Fragment Reassembly Timeout" message. */
-	ip_statistics.IpReasmTimeout++;
-	ip_statistics.IpReasmFails++;   
+	IP_INC_STATS_BH(IpReasmTimeout);
+	IP_INC_STATS_BH(IpReasmFails);
 	icmp_send(qp->fragments->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
 
 out:
@@ -395,7 +395,7 @@
 	iph = skb->nh.iph;
 	iph->frag_off = 0;
 	iph->tot_len = htons(count);
-	ip_statistics.IpReasmOKs++;
+	IP_INC_STATS_BH(IpReasmOKs);
 	return skb;
 
 out_invalid:
@@ -414,7 +414,7 @@
 			"Oversized IP packet from %d.%d.%d.%d.\n",
 			NIPQUAD(qp->iph->saddr));
 out_fail:
-	ip_statistics.IpReasmFails++;
+	IP_INC_STATS_BH(IpReasmFails);
 	return NULL;
 }
 
@@ -428,7 +428,7 @@
 	int flags, offset;
 	int i, ihl, end;
 	
-	ip_statistics.IpReasmReqds++;
+	IP_INC_STATS_BH(IpReasmReqds);
 
 	spin_lock(&ipfrag_lock);
 
@@ -599,7 +599,7 @@
 	/* the skb isn't in a fragment, so fall through to free it */
 out_freeskb:
 	kfree_skb(skb);
-	ip_statistics.IpReasmFails++;
+	IP_INC_STATS_BH(IpReasmFails);
 	if (qp)
 		goto out_timer;
 	goto out;
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ip_gre.c linux/net/ipv4/ip_gre.c
--- v2.3.38/linux/net/ipv4/ip_gre.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv4/ip_gre.c	Sat Jan  8 21:36:20 2000
@@ -790,7 +790,7 @@
 			iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit;
 #endif
 		else
-			iph->ttl = ip_statistics.IpDefaultTTL;
+			iph->ttl = sysctl_ip_default_ttl;
 	}
 
 	((u16*)(iph+1))[0] = tunnel->parms.o_flags;
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c
--- v2.3.38/linux/net/ipv4/ip_input.c	Thu Aug 26 13:05:45 1999
+++ linux/net/ipv4/ip_input.c	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.42 1999/08/20 11:05:27 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.44 2000/01/09 02:19:30 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -148,7 +148,7 @@
  *	SNMP management statistics
  */
 
-struct ip_mib ip_statistics={2,IPDEFTTL,};	/* Forwarding=No, Default TTL=64 */
+struct ip_mib ip_statistics[NR_CPUS*2];
 
 /*
  *	Process Router Attention IP option
@@ -368,7 +368,7 @@
 	return skb->dst->input(skb);
 
 inhdr_error:
-	ip_statistics.IpInHdrErrors++;
+	IP_INC_STATS_BH(IpInHdrErrors);
 drop:
         kfree_skb(skb);
         return(0);
@@ -387,7 +387,7 @@
 	if (skb->pkt_type == PACKET_OTHERHOST)
 		goto drop;
 
-	ip_statistics.IpInReceives++;
+	IP_INC_STATS_BH(IpInReceives);
 
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		goto out;
@@ -403,14 +403,14 @@
 	 *	4.	Doesn't have a bogus length
 	 */
 
-	if (skb->len < sizeof(struct iphdr))
+	if (skb->len < sizeof(struct iphdr) || skb->len < (iph->ihl<<2))
 		goto inhdr_error; 
 	if (iph->ihl < 5 || iph->version != 4 || ip_fast_csum((u8 *)iph, iph->ihl) != 0)
 		goto inhdr_error; 
 
 	{
 		__u32 len = ntohs(iph->tot_len); 
-		if (skb->len < len)
+		if (skb->len < len || len < (iph->ihl<<2))
 			goto inhdr_error;
 
 		/* Our transport medium may have padded the buffer out. Now we know it
@@ -424,7 +424,7 @@
 		       ip_rcv_finish);
 
 inhdr_error:
-	ip_statistics.IpInHdrErrors++;
+	IP_INC_STATS_BH(IpInHdrErrors);
 drop:
         kfree_skb(skb);
 out:
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.3.38/linux/net/ipv4/ip_output.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv4/ip_output.c	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.76 2000/01/06 00:41:57 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.77 2000/01/09 02:19:31 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -82,6 +82,7 @@
  */
 
 int sysctl_ip_dynaddr = 0;
+int sysctl_ip_default_ttl = IPDEFTTL;
 
 /* Generate a checksum for an outgoing IP datagram. */
 __inline__ void ip_send_check(struct iphdr *iph)
@@ -228,7 +229,7 @@
 	/*
 	 *	If the indicated interface is up and running, send the packet.
 	 */
-	ip_statistics.IpOutRequests++;
+	IP_INC_STATS(IpOutRequests);
 #ifdef CONFIG_IP_ROUTE_NAT
 	if (rt->rt_flags & RTCF_NAT)
 		ip_do_nat(skb);
@@ -285,7 +286,7 @@
 	struct rtable *rt = (struct rtable*)skb->dst;
 #endif
 
-	ip_statistics.IpOutRequests++;
+	IP_INC_STATS(IpOutRequests);
 
 #ifdef CONFIG_IP_ROUTE_NAT
 	if (rt->rt_flags&RTCF_NAT)
@@ -436,7 +437,7 @@
 		       ip_queue_xmit2);
 
 no_route:
-	ip_statistics.IpOutNoRoutes++;
+	IP_INC_STATS(IpOutNoRoutes);
 	kfree_skb(skb);
 	return -EHOSTUNREACH;
 }
@@ -644,14 +645,14 @@
 	} while (offset >= 0);
 
 	if (nfrags>1)
-		ip_statistics.IpFragCreates += nfrags;
+		ip_statistics[smp_processor_id()*2 + !in_interrupt()].IpFragCreates += nfrags;
 out:
 	return 0;
 
 error:
-	ip_statistics.IpOutDiscards++;
+	IP_INC_STATS(IpOutDiscards);
 	if (nfrags>1)
-		ip_statistics.IpFragCreates += nfrags;
+		ip_statistics[smp_processor_id()*2 + !in_interrupt()].IpFragCreates += nfrags;
 	return err; 
 }
 
@@ -757,7 +758,7 @@
 	err = -EFAULT;
 	kfree_skb(skb);
 error:
-	ip_statistics.IpOutDiscards++;
+	IP_INC_STATS(IpOutDiscards);
 	return err; 
 }
 
@@ -893,7 +894,7 @@
 		 *	Put this fragment into the sending queue.
 		 */
 
-		ip_statistics.IpFragCreates++;
+		IP_INC_STATS(IpFragCreates);
 
 		iph->tot_len = htons(len + hlen);
 
@@ -904,12 +905,12 @@
 			goto fail;
 	}
 	kfree_skb(skb);
-	ip_statistics.IpFragOKs++;
+	IP_INC_STATS(IpFragOKs);
 	return err;
 
 fail:
 	kfree_skb(skb); 
-	ip_statistics.IpFragFails++;
+	IP_INC_STATS(IpFragFails);
 	return err;
 }
 
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.3.38/linux/net/ipv4/ip_sockglue.c	Fri Sep 10 23:57:38 1999
+++ linux/net/ipv4/ip_sockglue.c	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
  *
  *		The IP to API glue.
  *		
- * Version:	$Id: ip_sockglue.c,v 1.45 1999/09/06 04:58:03 davem Exp $
+ * Version:	$Id: ip_sockglue.c,v 1.46 2000/01/09 02:19:32 davem Exp $
  *
  * Authors:	see ip.c
  *
@@ -479,7 +479,7 @@
 			if (optlen<1)
 				goto e_inval;
 			if(val==-1)
-				val = ip_statistics.IpDefaultTTL;
+				val = sysctl_ip_default_ttl;
 			if(val<1||val>255)
 				goto e_inval;
 			sk->protinfo.af_inet.ttl=val;
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.3.38/linux/net/ipv4/ipconfig.c	Thu Aug 26 13:05:45 1999
+++ linux/net/ipv4/ipconfig.c	Sat Jan  8 21:36:20 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.24 1999/08/20 00:35:14 davem Exp $
+ *  $Id: ipconfig.c,v 1.25 2000/01/09 02:19:31 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -116,7 +116,7 @@
 	unsigned short oflags;
 
 	last = &ic_first_dev;
-	read_lock(&dev_base_lock);
+	rtnl_shlock();
 	for (dev = dev_base; dev; dev = dev->next) {
 		if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
 		    (!(dev->flags & IFF_LOOPBACK) &&
@@ -148,7 +148,7 @@
 			DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able));
 		}
 	}
-	read_unlock(&dev_base_lock);
+	rtnl_shunlock();
 
 	*last = NULL;
 
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.3.38/linux/net/ipv4/ipmr.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv4/ipmr.c	Sat Jan  8 21:36:20 2000
@@ -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.49 2000/01/06 00:41:56 davem Exp $
+ *	Version: $Id: ipmr.c,v 1.50 2000/01/09 02:19:32 davem Exp $
  *
  *	Fixes:
  *	Michael Chastain	:	Incorrect size of copying.
@@ -1157,7 +1157,7 @@
 		   to blackhole.
 		 */
 
-		ip_statistics.IpFragFails++;
+		IP_INC_STATS_BH(IpFragFails);
 		ip_rt_put(rt);
 		return;
 	}
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.3.38/linux/net/ipv4/proc.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/proc.c	Sat Jan  8 21:36:20 2000
@@ -7,7 +7,7 @@
  *		PROC file system.  It is mainly used for debugging and
  *		statistics.
  *
- * Version:	$Id: proc.c,v 1.37 1999/12/15 22:39:19 davem Exp $
+ * Version:	$Id: proc.c,v 1.38 2000/01/09 02:19:30 davem Exp $
  *
  * Authors:	Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *		Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -50,6 +50,17 @@
 #include <net/sock.h>
 #include <net/raw.h>
 
+static int fold_prot_inuse(struct proto *proto)
+{
+	int res = 0;
+	int cpu;
+
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		res += proto->stats[cpu].inuse;
+
+	return res;
+}
+
 /*
  *	Report socket allocation statistics [mea@utu.fi]
  */
@@ -60,12 +71,12 @@
 
 	int len  = socket_get_info(buffer,start,offset,length);
 
-	len += sprintf(buffer+len,"TCP: inuse %d highest %d\n",
-		       tcp_prot.inuse, tcp_prot.highestinuse);
-	len += sprintf(buffer+len,"UDP: inuse %d highest %d\n",
-		       udp_prot.inuse, udp_prot.highestinuse);
-	len += sprintf(buffer+len,"RAW: inuse %d highest %d\n",
-		       raw_prot.inuse, raw_prot.highestinuse);
+	len += sprintf(buffer+len,"TCP: inuse %d\n",
+		       fold_prot_inuse(&tcp_prot));
+	len += sprintf(buffer+len,"UDP: inuse %d\n",
+		       fold_prot_inuse(&udp_prot));
+	len += sprintf(buffer+len,"RAW: inuse %d\n",
+		       fold_prot_inuse(&raw_prot));
 	if (offset >= len)
 	{
 		*start = buffer;
@@ -80,6 +91,17 @@
 	return len;
 }
 
+static unsigned long fold_field(unsigned long *begin, int sz, int nr)
+{
+	unsigned long res = 0;
+	int i;
+
+	sz /= sizeof(unsigned long);
+
+	for (i=0; i<2*smp_num_cpus; i++)
+		res += begin[i*sz + nr];
+	return res;
+}
 
 /* 
  *	Called from the PROCfs module. This outputs /proc/net/snmp.
@@ -87,65 +109,35 @@
  
 int snmp_get_info(char *buffer, char **start, off_t offset, int length)
 {
-	extern struct tcp_mib tcp_statistics;
-	extern struct udp_mib udp_statistics;
-	int len;
-/*
-  extern unsigned long tcp_rx_miss, tcp_rx_hit1,tcp_rx_hit2;
-*/
+	extern int sysctl_ip_default_ttl;
+	int len, i;
 
 	len = sprintf (buffer,
 		"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n"
-		"Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
-		    ip_statistics.IpForwarding, ip_statistics.IpDefaultTTL, 
-		    ip_statistics.IpInReceives, ip_statistics.IpInHdrErrors, 
-		    ip_statistics.IpInAddrErrors, ip_statistics.IpForwDatagrams, 
-		    ip_statistics.IpInUnknownProtos, ip_statistics.IpInDiscards, 
-		    ip_statistics.IpInDelivers, ip_statistics.IpOutRequests, 
-		    ip_statistics.IpOutDiscards, ip_statistics.IpOutNoRoutes, 
-		    ip_statistics.IpReasmTimeout, ip_statistics.IpReasmReqds, 
-		    ip_statistics.IpReasmOKs, ip_statistics.IpReasmFails, 
-		    ip_statistics.IpFragOKs, ip_statistics.IpFragFails, 
-		    ip_statistics.IpFragCreates);
-		    		
+		"Ip: %d %d", ipv4_devconf.forwarding ? 1 : 2, sysctl_ip_default_ttl);
+	for (i=0; i<offsetof(struct ip_mib, __pad)/sizeof(unsigned long); i++)
+		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)ip_statistics, sizeof(struct ip_mib), i));
+
 	len += sprintf (buffer + len,
-		"Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n"
-		"Icmp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
-		    icmp_statistics.IcmpInMsgs, icmp_statistics.IcmpInErrors,
-		    icmp_statistics.IcmpInDestUnreachs, icmp_statistics.IcmpInTimeExcds,
-		    icmp_statistics.IcmpInParmProbs, icmp_statistics.IcmpInSrcQuenchs,
-		    icmp_statistics.IcmpInRedirects, icmp_statistics.IcmpInEchos,
-		    icmp_statistics.IcmpInEchoReps, icmp_statistics.IcmpInTimestamps,
-		    icmp_statistics.IcmpInTimestampReps, icmp_statistics.IcmpInAddrMasks,
-		    icmp_statistics.IcmpInAddrMaskReps, icmp_statistics.IcmpOutMsgs,
-		    icmp_statistics.IcmpOutErrors, icmp_statistics.IcmpOutDestUnreachs,
-		    icmp_statistics.IcmpOutTimeExcds, icmp_statistics.IcmpOutParmProbs,
-		    icmp_statistics.IcmpOutSrcQuenchs, icmp_statistics.IcmpOutRedirects,
-		    icmp_statistics.IcmpOutEchos, icmp_statistics.IcmpOutEchoReps,
-		    icmp_statistics.IcmpOutTimestamps, icmp_statistics.IcmpOutTimestampReps,
-		    icmp_statistics.IcmpOutAddrMasks, icmp_statistics.IcmpOutAddrMaskReps);
-	
+		"\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n"
+		  "Icmp:");
+	for (i=0; i<offsetof(struct icmp_mib, __pad)/sizeof(unsigned long); i++)
+		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)icmp_statistics, sizeof(struct icmp_mib), i));
+
 	len += sprintf (buffer + len,
-		"Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
-		"Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
-		    tcp_statistics.TcpRtoAlgorithm, tcp_statistics.TcpRtoMin,
-		    tcp_statistics.TcpRtoMax, tcp_statistics.TcpMaxConn,
-		    tcp_statistics.TcpActiveOpens, tcp_statistics.TcpPassiveOpens,
-		    tcp_statistics.TcpAttemptFails, tcp_statistics.TcpEstabResets,
-		    tcp_statistics.TcpCurrEstab, tcp_statistics.TcpInSegs,
-		    tcp_statistics.TcpOutSegs, tcp_statistics.TcpRetransSegs,
-		    tcp_statistics.TcpInErrs, tcp_statistics.TcpOutRsts);
-		
+		"\nTcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
+		  "Tcp:");
+	for (i=0; i<offsetof(struct tcp_mib, __pad)/sizeof(unsigned long); i++)
+		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)tcp_statistics, sizeof(struct tcp_mib), i));
+
 	len += sprintf (buffer + len,
-		"Udp: InDatagrams NoPorts InErrors OutDatagrams\nUdp: %lu %lu %lu %lu\n",
-		    udp_statistics.UdpInDatagrams, udp_statistics.UdpNoPorts,
-		    udp_statistics.UdpInErrors, udp_statistics.UdpOutDatagrams);	    
-/*	
-	  len += sprintf( buffer + len,
-	  	"TCP fast path RX:  H2: %ul H1: %ul L: %ul\n",
-	  		tcp_rx_hit2,tcp_rx_hit1,tcp_rx_miss);
-*/
-	
+		"\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n"
+		  "Udp:");
+	for (i=0; i<offsetof(struct udp_mib, __pad)/sizeof(unsigned long); i++)
+		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)udp_statistics, sizeof(struct udp_mib), i));
+
+	len += sprintf (buffer + len, "\n");
+
 	if (offset >= len)
 	{
 		*start = buffer;
@@ -166,23 +158,17 @@
  
 int netstat_get_info(char *buffer, char **start, off_t offset, int length)
 {
-	extern struct linux_mib net_statistics;
-	int len;
+	int len, i;
 
 	len = sprintf(buffer,
 		      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
 		      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
 		      " OutOfWindowIcmps LockDroppedIcmps\n" 	
-		      "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
-		      net_statistics.SyncookiesSent,
-		      net_statistics.SyncookiesRecv,
-		      net_statistics.SyncookiesFailed,
-		      net_statistics.EmbryonicRsts,
-		      net_statistics.PruneCalled,
-		      net_statistics.RcvPruned,
-		      net_statistics.OfoPruned,
-		      net_statistics.OutOfWindowIcmps,
-		      net_statistics.LockDroppedIcmps);
+		      "TcpExt:");
+	for (i=0; i<offsetof(struct linux_mib, __pad)/sizeof(unsigned long); i++)
+		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)net_statistics, sizeof(struct linux_mib), i));
+
+	len += sprintf (buffer + len, "\n");
 
 	if (offset >= len)
 	{
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.3.38/linux/net/ipv4/raw.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv4/raw.c	Sat Jan  8 21:36:20 2000
@@ -5,7 +5,7 @@
  *
  *		RAW - implementation of IP "raw" sockets.
  *
- * Version:	$Id: raw.c,v 1.45 2000/01/06 00:41:58 davem Exp $
+ * Version:	$Id: raw.c,v 1.46 2000/01/09 02:19:30 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -75,9 +75,7 @@
 		(*skp)->pprev = &sk->next;
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
  	sock_hold(sk);
 	write_unlock_bh(&raw_v4_lock);
 }
@@ -90,7 +88,7 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
-		sk->prot->inuse--;
+		sock_prot_dec_use(sk->prot);
 		__sock_put(sk);
 	}
 	write_unlock_bh(&raw_v4_lock);
@@ -214,7 +212,7 @@
 
 	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 || harderr) {
 		sk->err = err;
 		sk->error_report(sk);
@@ -227,12 +225,12 @@
 	
 	if (sock_queue_rcv_skb(sk,skb)<0)
 	{
-		ip_statistics.IpInDiscards++;
+		IP_INC_STATS(IpInDiscards);
 		kfree_skb(skb);
 		return -1;
 	}
 
-	ip_statistics.IpInDelivers++;
+	IP_INC_STATS(IpInDelivers);
 	return 0;
 }
 
@@ -674,6 +672,4 @@
 	128,				/* max_header */
 	0,				/* retransmits */
 	"RAW",				/* name */
-	0,				/* inuse */
-	0				/* highestinuse */
 };
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/syncookies.c linux/net/ipv4/syncookies.c
--- v2.3.38/linux/net/ipv4/syncookies.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipv4/syncookies.c	Sat Jan  8 21:36:20 2000
@@ -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.9 1999/08/23 06:30:34 davem Exp $
+ *  $Id: syncookies.c,v 1.10 2000/01/09 02:19:35 davem Exp $
  *
  *  Missing: IPv6 support. 
  */
@@ -60,7 +60,7 @@
 		;
 	*mssp = msstab[mssind]+1;
 
-	net_statistics.SyncookiesSent++;
+	NET_INC_STATS_BH(SyncookiesSent);
 
 	return secure_tcp_syn_cookie(skb->nh.iph->saddr, skb->nh.iph->daddr,
 				     skb->h.th->source, skb->h.th->dest,
@@ -137,11 +137,11 @@
 
 	mss = cookie_check(skb, cookie);
 	if (mss == 0) {
-	 	net_statistics.SyncookiesFailed++;
+	 	NET_INC_STATS_BH(SyncookiesFailed);
 		return sk;
 	}
 
-	net_statistics.SyncookiesRecv++;
+	NET_INC_STATS_BH(SyncookiesRecv);
 
 	req = tcp_openreq_alloc();
 	if (req == NULL)
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.3.38/linux/net/ipv4/sysctl_net_ipv4.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv4/sysctl_net_ipv4.c	Sat Jan  8 21:36:20 2000
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.41 2000/01/06 00:42:03 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.42 2000/01/09 02:19:37 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -132,7 +132,7 @@
          &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
          &ipv4_sysctl_forward,&ipv4_sysctl_forward_strategy},
         {NET_IPV4_DEFAULT_TTL, "ip_default_ttl",
-         &ip_statistics.IpDefaultTTL, sizeof(int), 0644, NULL,
+         &sysctl_ip_default_ttl, sizeof(int), 0644, NULL,
          &proc_dointvec},
         {NET_IPV4_AUTOCONFIG, "ip_autoconfig",
          &ipv4_config.autoconfig, sizeof(int), 0644, NULL,
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.38/linux/net/ipv4/tcp.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/tcp.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.152 1999/11/23 08:57:03 davem Exp $
+ * Version:	$Id: tcp.c,v 1.153 2000/01/09 02:19:33 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -426,7 +426,7 @@
 
 int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
 
-struct tcp_mib	tcp_statistics;
+struct tcp_mib	tcp_statistics[NR_CPUS*2];
 
 kmem_cache_t *tcp_openreq_cachep;
 kmem_cache_t *tcp_bucket_cachep;
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.38/linux/net/ipv4/tcp_input.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv4/tcp_input.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.176 1999/12/20 05:19:46 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.177 2000/01/09 02:19:39 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1314,7 +1314,7 @@
 	spin_unlock(&bhead->lock);
 
 	/* Step 4: Un-charge protocol socket in-use count. */
-	sk->prot->inuse--;
+	sock_prot_dec_use(sk->prot);
 }
 
 /* 
@@ -1365,7 +1365,7 @@
 
 		/* CLOSE the SK. */
 		if(sk->state == TCP_ESTABLISHED)
-			tcp_statistics.TcpCurrEstab--;
+			tcp_statistics[smp_processor_id()*2].TcpCurrEstab--;
 		sk->state = TCP_CLOSE;
 	} else {
 		/* Sorry, we're out of memory, just CLOSE this
@@ -2018,13 +2018,13 @@
 
 	SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq);
 
-	net_statistics.PruneCalled++; 
+	NET_INC_STATS_BH(PruneCalled);
 
 	/* First, purge the out_of_order queue. */
 	skb = __skb_dequeue_tail(&tp->out_of_order_queue);
 	if(skb != NULL) {
 		/* Free it all. */
-		do {	net_statistics.OfoPruned += skb->len; 
+		do {	net_statistics[smp_processor_id()*2].OfoPruned += skb->len; 
 			kfree_skb(skb);
 			skb = __skb_dequeue_tail(&tp->out_of_order_queue);
 		} while(skb != NULL);
@@ -2179,7 +2179,7 @@
 				tcp_data_snd_check(sk);
 				return 0;
 			} else { /* Header too small */
-				tcp_statistics.TcpInErrs++;
+				TCP_INC_STATS_BH(TcpInErrs);
 				goto discard;
 			}
 		} else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una &&
@@ -2267,7 +2267,7 @@
 
 	if(th->syn && TCP_SKB_CB(skb)->seq != tp->syn_seq) {
 		SOCK_DEBUG(sk, "syn in established state\n");
-		tcp_statistics.TcpInErrs++;
+		TCP_INC_STATS_BH(TcpInErrs);
 		tcp_reset(sk);
 		return 1;
 	}
@@ -2592,7 +2592,7 @@
 	tp->syn_backlog--;
 	tcp_dec_slow_timer(TCP_SLT_SYNACK);
 
-	net_statistics.EmbryonicRsts++;
+	NET_INC_STATS_BH(EmbryonicRsts);
 	if (!(flg & TCP_FLAG_RST))
 		req->class->send_reset(skb);
 
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.38/linux/net/ipv4/tcp_ipv4.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv4/tcp_ipv4.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.193 2000/01/06 00:42:01 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.194 2000/01/09 02:19:41 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -443,9 +443,7 @@
 		(*skp)->pprev = &sk->next;
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
 	write_unlock(lock);
 }
 
@@ -477,7 +475,7 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
-		sk->prot->inuse--;
+		sock_prot_dec_use(sk->prot);
 	}
 	write_unlock_bh(lock);
 }
@@ -670,9 +668,7 @@
 
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
 	write_unlock_bh(&head->lock);
 
 #ifdef CONFIG_TCP_TW_RECYCLE
@@ -978,7 +974,7 @@
 	int err;
 
 	if (len < (iph->ihl << 2) + ICMP_MIN_LENGTH) { 
-		icmp_statistics.IcmpInErrors++; 
+		ICMP_INC_STATS_BH(IcmpInErrors); 
 		return;
 	}
 #if ICMP_MIN_LENGTH < 14
@@ -990,7 +986,7 @@
 
 	sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, skb->dev->ifindex);
 	if (sk == NULL) {
-		icmp_statistics.IcmpInErrors++;
+		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
 	if (sk->state == TCP_TIME_WAIT) {
@@ -1003,12 +999,12 @@
 	 * servers this needs to be solved differently.
 	 */
 	if (sk->lock.users != 0)
-		net_statistics.LockDroppedIcmps++;
+		NET_INC_STATS_BH(LockDroppedIcmps);
 
 	tp = &sk->tp_pinfo.af_tcp;
 	seq = ntohl(th->seq);
 	if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) {
-		net_statistics.OutOfWindowIcmps++;
+		NET_INC_STATS(OutOfWindowIcmps);
 		goto out;
 	}
 
@@ -1082,12 +1078,12 @@
 			BUG_TRAP(sk->lock.users == 0);
 			tp = &sk->tp_pinfo.af_tcp;
 			if (!between(seq, tp->snd_una, tp->snd_nxt)) {
-				net_statistics.OutOfWindowIcmps++;
+				NET_INC_STATS(OutOfWindowIcmps);
 				goto out;
 			}
 		} else {
 			if (seq != req->snt_isn) {
-				net_statistics.OutOfWindowIcmps++;
+				NET_INC_STATS(OutOfWindowIcmps);
 				goto out;
 			}
 
@@ -1112,7 +1108,7 @@
 		if (!no_flags && !th->syn)
 			goto out;
 		if (sk->lock.users == 0) {
-			tcp_statistics.TcpAttemptFails++;
+			TCP_INC_STATS_BH(TcpAttemptFails);
 			sk->err = err;
 			/* Wake people up to see the error (see connect in sock.c) */
 			sk->error_report(sk);
@@ -1216,8 +1212,8 @@
 
 	ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
 
-	tcp_statistics.TcpOutSegs++;
-	tcp_statistics.TcpOutRsts++;
+	TCP_INC_STATS_BH(TcpOutSegs);
+	TCP_INC_STATS_BH(TcpOutRsts);
 }
 
 /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states
@@ -1267,7 +1263,7 @@
 
 	ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len);
 
-	tcp_statistics.TcpOutSegs++;
+	TCP_INC_STATS_BH(TcpOutSegs);
 }
 
 static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
@@ -1303,12 +1299,12 @@
 			   req->af.v4_req.loc_addr,
 			   RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
 			   sk->bound_dev_if)) {
-		ip_statistics.IpOutNoRoutes++;
+		IP_INC_STATS_BH(IpOutNoRoutes);
 		return;
 	}
 	if(opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) {
 		ip_rt_put(rt);
-		ip_statistics.IpOutNoRoutes++;
+		IP_INC_STATS_BH(IpOutNoRoutes);
 		return;
 	}
 
@@ -1488,7 +1484,7 @@
 	if (!want_cookie) 
 		BACKLOG(sk)--;
 drop:
-	tcp_statistics.TcpAttemptFails++;
+	TCP_INC_STATS_BH(TcpAttemptFails);
 	return 0;
 }
 
@@ -1692,7 +1688,7 @@
 	return 0;
 
 csum_err:
-	tcp_statistics.TcpInErrs++;
+	TCP_INC_STATS_BH(TcpInErrs);
 	goto discard;
 }
 
@@ -1715,7 +1711,7 @@
 	__skb_pull(skb, skb->h.raw - skb->data);
 
 	/* Count it even if it's bad */
-	tcp_statistics.TcpInSegs++;
+	TCP_INC_STATS_BH(TcpInSegs);
 
 	if (len < sizeof(struct tcphdr))
 		goto bad_packet;
@@ -1755,7 +1751,7 @@
 no_tcp_socket:
 	if (tcp_csum_verify(skb)) {
 bad_packet:
-		tcp_statistics.TcpInErrs++;
+		TCP_INC_STATS_BH(TcpInErrs);
 	} else {
 		tcp_v4_send_reset(skb);
 	}
@@ -1771,7 +1767,7 @@
 
 do_time_wait:
 	if (tcp_csum_verify(skb)) {
-		tcp_statistics.TcpInErrs++;
+		TCP_INC_STATS_BH(TcpInErrs);
 		goto discard_and_relse;
 	}
 	switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
@@ -2218,11 +2214,7 @@
 	128,				/* max_header */
 	0,				/* retransmits */
 	"TCP",				/* name */
-	0,				/* inuse */
-	0				/* highestinuse */
 };
-
-
 
 void __init tcp_v4_init(struct net_proto_family *ops)
 {
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.3.38/linux/net/ipv4/tcp_output.c	Fri Sep 10 23:57:38 1999
+++ linux/net/ipv4/tcp_output.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.113 1999/09/07 02:31:39 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.114 2000/01/09 02:19:43 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -192,7 +192,7 @@
 
 		clear_delayed_acks(sk);
 		tp->last_ack_sent = tp->rcv_nxt;
-		tcp_statistics.TcpOutSegs++;
+		TCP_INC_STATS(TcpOutSegs);
 		tp->af_specific->queue_xmit(skb);
 	}
 #undef SYSCTL_FLAG_TSTAMPS
@@ -677,7 +677,7 @@
 
 	/* Update global TCP statistics and return success. */
 	sk->prot->retransmits++;
-	tcp_statistics.TcpRetransSegs++;
+	TCP_INC_STATS(TcpRetransSegs);
 
 	return 0;
 }
@@ -941,7 +941,7 @@
 
 	skb->csum = 0;
 	th->doff = (tcp_header_size >> 2);
-	tcp_statistics.TcpOutSegs++;
+	TCP_INC_STATS(TcpOutSegs);
 	return skb;
 }
 
@@ -1009,7 +1009,7 @@
 	__skb_queue_tail(&sk->write_queue, buff);
 	tp->packets_out++;
 	tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL));
-	tcp_statistics.TcpActiveOpens++;
+	TCP_INC_STATS(TcpActiveOpens);
 
 	/* Timer for repeating the SYN until an answer. */
 	tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
diff -u --recursive --new-file v2.3.38/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.3.38/linux/net/ipv4/udp.c	Fri Jan  7 19:13:23 2000
+++ linux/net/ipv4/udp.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.76 2000/01/05 21:27:51 davem Exp $
+ * Version:	$Id: udp.c,v 1.77 2000/01/09 02:19:44 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -120,7 +120,7 @@
  *	Snmp MIB for the UDP layer
  */
 
-struct udp_mib		udp_statistics;
+struct udp_mib		udp_statistics[NR_CPUS*2];
 
 struct sock *udp_hash[UDP_HTABLE_SIZE];
 rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED;
@@ -205,9 +205,7 @@
 		(*skp)->pprev = &sk->next;
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
  	sock_hold(sk);
 	write_unlock_bh(&udp_hash_lock);
 }
@@ -220,7 +218,7 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
-		sk->prot->inuse--;
+		sock_prot_dec_use(sk->prot);
 		__sock_put(sk);
 	}
 	write_unlock_bh(&udp_hash_lock);
@@ -326,13 +324,13 @@
 	int err;
 
 	if (len < (iph->ihl<<2)+sizeof(struct udphdr)) {
-		icmp_statistics.IcmpInErrors++;
+		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_statistics.IcmpInErrors++;
+		ICMP_INC_STATS_BH(IcmpInErrors);
     	  	return;	/* No socket for error */
 	}
 
@@ -610,7 +608,7 @@
 	if (free)
 		kfree(ipc.opt);
 	if (!err) {
-		udp_statistics.UdpOutDatagrams++;
+		UDP_INC_STATS_USER(UdpOutDatagrams);
 		return len;
 	}
 	return err;
@@ -748,7 +746,7 @@
 
 #ifdef CONFIG_UDP_DELAY_CSUM
 csum_copy_err:
-	udp_statistics.UdpInErrors++;
+	UDP_INC_STATS_BH(UdpInErrors);
 
 	/* Clear queue. */
 	if (flags&MSG_PEEK) {
@@ -836,9 +834,9 @@
 #if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM)
 	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
 		if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
-			udp_statistics.UdpInErrors++;
-			ip_statistics.IpInDiscards++;
-			ip_statistics.IpInDelivers--;
+			UDP_INC_STATS_BH(UdpInErrors);
+			IP_INC_STATS_BH(IpInDiscards);
+			ip_statistics[smp_processor_id()*2].IpInDelivers--;
 			kfree_skb(skb);
 			return -1;
 		}
@@ -847,13 +845,13 @@
 #endif
 
 	if (sock_queue_rcv_skb(sk,skb)<0) {
-		udp_statistics.UdpInErrors++;
-		ip_statistics.IpInDiscards++;
-		ip_statistics.IpInDelivers--;
+		UDP_INC_STATS_BH(UdpInErrors);
+		IP_INC_STATS_BH(IpInDiscards);
+		ip_statistics[smp_processor_id()*2].IpInDelivers--;
 		kfree_skb(skb);
 		return -1;
 	}
-	udp_statistics.UdpInDatagrams++;
+	UDP_INC_STATS_BH(UdpInDatagrams);
 	return 0;
 }
 
@@ -947,7 +945,7 @@
   	uh = skb->h.uh;
 	__skb_pull(skb, skb->h.raw - skb->data);
 
-  	ip_statistics.IpInDelivers++;
+  	IP_INC_STATS_BH(IpInDelivers);
 
 	/*
 	 *	Validate the packet and the UDP length.
@@ -957,7 +955,7 @@
 
 	if (ulen > len || ulen < sizeof(*uh)) {
 		NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
-		udp_statistics.UdpInErrors++;
+		UDP_INC_STATS_BH(UdpInErrors);
 		kfree_skb(skb);
 		return(0);
 	}
@@ -983,7 +981,7 @@
 		if (udp_checksum_verify(skb, uh, ulen, saddr, daddr, 0))
 			goto csum_error;
 
-  		udp_statistics.UdpNoPorts++;
+		UDP_INC_STATS_BH(UdpNoPorts);
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 
 		/*
@@ -1019,7 +1017,7 @@
 			NIPQUAD(daddr),
 			ntohs(uh->dest),
 			ulen));
-	udp_statistics.UdpInErrors++;
+	UDP_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);
 }
@@ -1112,6 +1110,4 @@
 	128,				/* max_header */
 	0,				/* retransmits */
  	"UDP",				/* name */
-	0,				/* inuse */
-	0				/* highestinuse */
 };
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/exthdrs.c linux/net/ipv6/exthdrs.c
--- v2.3.38/linux/net/ipv6/exthdrs.c	Wed May 26 18:14:38 1999
+++ linux/net/ipv6/exthdrs.c	Sat Jan  8 21:36:21 2000
@@ -7,7 +7,7 @@
  *	Andi Kleen		<ak@muc.de>
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: exthdrs.c,v 1.9 1999/05/17 23:47:35 davem Exp $
+ *	$Id: exthdrs.c,v 1.10 2000/01/09 02:19: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
@@ -198,7 +198,7 @@
 	struct rt0_hdr *rthdr;
 
 	if (((hdr->hdrlen+1)<<3) > skb->tail - skb->h.raw) {
-		ipv6_statistics.Ip6InHdrErrors++;
+		IP6_INC_STATS_BH(Ip6InHdrErrors);
 		kfree_skb(skb);
 		return NULL;
 	}
@@ -468,7 +468,7 @@
 	}
 
 	if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
-		ipv6_statistics.Ip6InTruncatedPkts++;
+		IP6_INC_STATS_BH(Ip6InTruncatedPkts);
 		goto drop;
 	}
 	skb_trim(skb, pkt_len + sizeof(struct ipv6hdr));
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c
--- v2.3.38/linux/net/ipv6/icmp.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipv6/icmp.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>
  *
- *	$Id: icmp.c,v 1.24 1999/08/20 11:06:18 davem Exp $
+ *	$Id: icmp.c,v 1.25 2000/01/09 02:19:54 davem Exp $
  *
  *	Based on net/ipv4/icmp.c
  *
@@ -58,7 +58,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-struct icmpv6_mib icmpv6_statistics;
+struct icmpv6_mib icmpv6_statistics[NR_CPUS*2];
 
 /*
  *	ICMP socket for flow control.
@@ -237,7 +237,7 @@
 	 */
 	dst = ip6_route_output(sk, fl);
 	if (dst->error) {
-		ipv6_statistics.Ip6OutNoRoutes++;
+		IP6_INC_STATS(Ip6OutNoRoutes);
 	} else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
 		res = 1;
 	} else {
@@ -388,8 +388,8 @@
 	ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
 		       MSG_DONTWAIT);
 	if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
-		(&icmpv6_statistics.Icmp6OutDestUnreachs)[type-1]++;
-	icmpv6_statistics.Icmp6OutMsgs++;
+		(&(icmpv6_statistics[smp_processor_id()*2].Icmp6OutDestUnreachs))[type-1]++;
+	ICMP6_INC_STATS_BH(Icmp6OutMsgs);
 out:
 	icmpv6_xmit_unlock();
 }
@@ -439,8 +439,8 @@
 
 	ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
 		       MSG_DONTWAIT);
-	icmpv6_statistics.Icmp6OutEchoReplies++;
-	icmpv6_statistics.Icmp6OutMsgs++;
+	ICMP6_INC_STATS_BH(Icmp6OutEchoReplies);
+	ICMP6_INC_STATS_BH(Icmp6OutMsgs);
 
 	icmpv6_xmit_unlock_bh();
 }
@@ -513,7 +513,7 @@
 	int ulen;
 	int type;
 
-	icmpv6_statistics.Icmp6InMsgs++;
+	ICMP6_INC_STATS_BH(Icmp6InMsgs);
 
 	if (len < sizeof(struct icmp6hdr))
 		goto discard_it;
@@ -556,9 +556,9 @@
 	type = hdr->icmp6_type;
 
 	if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
-		(&icmpv6_statistics.Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++;
+		(&icmpv6_statistics[smp_processor_id()*2].Icmp6InDestUnreachs)[type-ICMPV6_DEST_UNREACH]++;
 	else if (type >= ICMPV6_ECHO_REQUEST && type <= NDISC_REDIRECT)
-		(&icmpv6_statistics.Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++;
+		(&icmpv6_statistics[smp_processor_id()*2].Icmp6InEchos)[type-ICMPV6_ECHO_REQUEST]++;
 
 	switch (type) {
 
@@ -631,7 +631,7 @@
 	return 0;
 
 discard_it:
-	icmpv6_statistics.Icmp6InErrors++;
+	ICMP6_INC_STATS_BH(Icmp6InErrors);
 	kfree_skb(skb);
 	return 0;
 }
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/ip6_input.c linux/net/ipv6/ip6_input.c
--- v2.3.38/linux/net/ipv6/ip6_input.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv6/ip6_input.c	Sat Jan  8 21:36:21 2000
@@ -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.14 1999/08/30 12:14:56 davem Exp $
+ *	$Id: ip6_input.c,v 1.15 2000/01/09 02:19:54 davem Exp $
  *
  *	Based in linux/net/ipv4/ip_input.c
  *
@@ -46,7 +46,7 @@
 	if (skb->pkt_type == PACKET_OTHERHOST)
 		goto drop;
 
-	ipv6_statistics.Ip6InReceives++;
+	IP6_INC_STATS_BH(Ip6InReceives);
 
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		goto out;
@@ -73,7 +73,7 @@
 	if (hdr->nexthdr == NEXTHDR_HOP) {
 		skb->h.raw = (u8*)(hdr+1);
 		if (!ipv6_parse_hopopts(skb, &hdr->nexthdr)) {
-			ipv6_statistics.Ip6InHdrErrors++;
+			IP6_INC_STATS_BH(Ip6InHdrErrors);
 			return 0;
 		}
 	}
@@ -84,9 +84,9 @@
 	return skb->dst->input(skb);
 
 truncated:
-	ipv6_statistics.Ip6InTruncatedPkts++;
+	IP6_INC_STATS_BH(Ip6InTruncatedPkts);
 err:
-	ipv6_statistics.Ip6InHdrErrors++;
+	IP6_INC_STATS_BH(Ip6InHdrErrors);
 drop:
 	kfree_skb(skb);
 out:
@@ -175,7 +175,7 @@
 	 *	not found: send ICMP parameter problem back
 	 */
 	if (!found) {
-		ipv6_statistics.Ip6InUnknownProtos++;
+		IP6_INC_STATS_BH(Ip6InUnknownProtos);
 		icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhptr);
 	}
 
@@ -188,7 +188,7 @@
 	int deliver = 0;
 	int discard = 1;
 
-	ipv6_statistics.Ip6InMcastPkts++;
+	IP6_INC_STATS_BH(Ip6InMcastPkts);
 
 	hdr = skb->nh.ipv6h;
 	if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr))
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/ip6_output.c linux/net/ipv6/ip6_output.c
--- v2.3.38/linux/net/ipv6/ip6_output.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv6/ip6_output.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: ip6_output.c,v 1.23 2000/01/06 00:42:07 davem Exp $
+ *	$Id: ip6_output.c,v 1.24 2000/01/09 02:19:49 davem Exp $
  *
  *	Based on linux/net/ipv4/ip_output.c
  *
@@ -81,7 +81,7 @@
 			}
 		}
 
-		ipv6_statistics.Ip6OutMcastPkts++;
+		IP6_INC_STATS(Ip6OutMcastPkts);
 	}
 
 	if (hh) {
@@ -158,7 +158,7 @@
 	ipv6_addr_copy(&hdr->daddr, first_hop);
 
 	if (skb->len <= dst->pmtu) {
-		ipv6_statistics.Ip6OutRequests++;
+		IP6_INC_STATS(Ip6OutRequests);
 		return dst->output(skb);
 	}
 
@@ -358,7 +358,7 @@
 			skb = skb_copy(last_skb, sk->allocation);
 
 			if (skb == NULL) {
-				ipv6_statistics.Ip6FragFails++;
+				IP6_INC_STATS(Ip6FragFails);
 				kfree_skb(last_skb);
 				return -ENOMEM;
 			}
@@ -386,8 +386,8 @@
 				break;
 			}
 
-			ipv6_statistics.Ip6FragCreates++;
-			ipv6_statistics.Ip6OutRequests++;
+			IP6_INC_STATS(Ip6FragCreates);
+			IP6_INC_STATS(Ip6OutRequests);
 			err = dst->output(skb);
 			if (err) {
 				kfree_skb(last_skb);
@@ -397,7 +397,7 @@
 	}
 
 	if (err) {
-		ipv6_statistics.Ip6FragFails++;
+		IP6_INC_STATS(Ip6FragFails);
 		kfree_skb(last_skb);
 		return -EFAULT;
 	}
@@ -411,9 +411,9 @@
 
 	skb_put(last_skb, last_len);
 
-	ipv6_statistics.Ip6FragCreates++;
-	ipv6_statistics.Ip6FragOKs++;
-	ipv6_statistics.Ip6OutRequests++;
+	IP6_INC_STATS(Ip6FragCreates);
+	IP6_INC_STATS(Ip6FragOKs);
+	IP6_INC_STATS(Ip6OutRequests);
 	return dst->output(last_skb);
 }
 
@@ -473,7 +473,7 @@
 		dst = ip6_route_output(sk, fl);
 
 	if (dst->error) {
-		ipv6_statistics.Ip6OutNoRoutes++;
+		IP6_INC_STATS(Ip6OutNoRoutes);
 		dst_release(dst);
 		return -ENETUNREACH;
 	}
@@ -552,7 +552,7 @@
 					  flags & MSG_DONTWAIT, &err);
 
 		if (skb == NULL) {
-			ipv6_statistics.Ip6OutDiscards++;
+			IP6_INC_STATS(Ip6OutDiscards);
 			goto out;
 		}
 
@@ -581,7 +581,7 @@
 			      0, length);
 
 		if (!err) {
-			ipv6_statistics.Ip6OutRequests++;
+			IP6_INC_STATS(Ip6OutRequests);
 			err = dst->output(skb);
 		} else {
 			err = -EFAULT;
@@ -711,7 +711,7 @@
 		/* Again, force OUTPUT device used as source address */
 		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
-		ipv6_statistics.Ip6InTooBigErrors++;
+		IP6_INC_STATS_BH(Ip6InTooBigErrors);
 		kfree_skb(skb);
 		return -EMSGSIZE;
 	}
@@ -725,11 +725,11 @@
  
 	hdr->hop_limit--;
 
-	ipv6_statistics.Ip6OutForwDatagrams++;
+	IP6_INC_STATS_BH(Ip6OutForwDatagrams);
 	return dst->output(skb);
 
 drop:
-	ipv6_statistics.Ip6InAddrErrors++;
+	IP6_INC_STATS_BH(Ip6InAddrErrors);
 	kfree_skb(skb);
 	return -EINVAL;
 }
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c
--- v2.3.38/linux/net/ipv6/ipv6_sockglue.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv6/ipv6_sockglue.c	Sat Jan  8 21:36:21 2000
@@ -7,7 +7,7 @@
  *
  *	Based on linux/net/ipv4/ip_sockglue.c
  *
- *	$Id: ipv6_sockglue.c,v 1.29 1999/08/31 07:04:06 davem Exp $
+ *	$Id: ipv6_sockglue.c,v 1.30 2000/01/09 02:19:49 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -50,7 +50,8 @@
 
 #include <asm/uaccess.h>
 
-struct ipv6_mib ipv6_statistics={0, };
+struct ipv6_mib ipv6_statistics[NR_CPUS*2];
+
 struct packet_type ipv6_packet_type =
 {
 	__constant_htons(ETH_P_IPV6), 
@@ -165,13 +166,21 @@
 
 			if (sk->protocol == IPPROTO_TCP) {
 				struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-				
+
+				local_bh_disable();
+				sock_prot_dec_use(sk->prot);
+				sock_prot_inc_use(&tcp_prot);
+				local_bh_enable();
 				sk->prot = &tcp_prot;
 				tp->af_specific = &ipv4_specific;
 				sk->socket->ops = &inet_stream_ops;
 				sk->family = PF_INET;
 				tcp_sync_mss(sk, tp->pmtu_cookie);
 			} else {
+				local_bh_disable();
+				sock_prot_dec_use(sk->prot);
+				sock_prot_inc_use(&udp_prot);
+				local_bh_enable();
 				sk->prot = &udp_prot;
 				sk->socket->ops = &inet_dgram_ops;
 			}
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c
--- v2.3.38/linux/net/ipv6/mcast.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv6/mcast.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: mcast.c,v 1.27 1999/12/09 00:52:49 davem Exp $
+ *	$Id: mcast.c,v 1.28 2000/01/09 02:19:50 davem Exp $
  *
  *	Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c 
  *
@@ -528,10 +528,10 @@
 
 	dev_queue_xmit(skb);
 	if (type == ICMPV6_MGM_REDUCTION)
-		icmpv6_statistics.Icmp6OutGroupMembReductions++;
+		ICMP6_INC_STATS(Icmp6OutGroupMembReductions);
 	else
-		icmpv6_statistics.Icmp6OutGroupMembResponses++;
-	icmpv6_statistics.Icmp6OutMsgs++;
+		ICMP6_INC_STATS(Icmp6OutGroupMembResponses);
+	ICMP6_INC_STATS(Icmp6OutMsgs);
 }
 
 static void igmp6_join_group(struct ifmcaddr6 *ma)
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- v2.3.38/linux/net/ipv6/ndisc.c	Tue Nov 23 22:42:21 1999
+++ linux/net/ipv6/ndisc.c	Sat Jan  8 21:36:21 2000
@@ -374,8 +374,8 @@
 
 	dev_queue_xmit(skb);
 
-	icmpv6_statistics.Icmp6OutNeighborAdvertisements++;
-	icmpv6_statistics.Icmp6OutMsgs++;
+	ICMP6_INC_STATS(Icmp6OutNeighborAdvertisements);
+	ICMP6_INC_STATS(Icmp6OutMsgs);
 }        
 
 void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
@@ -436,8 +436,8 @@
 	/* send it! */
 	dev_queue_xmit(skb);
 
-	icmpv6_statistics.Icmp6OutNeighborSolicits++;
-	icmpv6_statistics.Icmp6OutMsgs++;
+	ICMP6_INC_STATS(Icmp6OutNeighborSolicits);
+	ICMP6_INC_STATS(Icmp6OutMsgs);
 }
 
 void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
@@ -487,8 +487,8 @@
 	/* send it! */
 	dev_queue_xmit(skb);
 
-	icmpv6_statistics.Icmp6OutRouterSolicits++;
-	icmpv6_statistics.Icmp6OutMsgs++;
+	ICMP6_INC_STATS(Icmp6OutRouterSolicits);
+	ICMP6_INC_STATS(Icmp6OutMsgs);
 }
 		   
 
@@ -912,8 +912,8 @@
 
 	dev_queue_xmit(buff);
 
-	icmpv6_statistics.Icmp6OutRedirects++;
-	icmpv6_statistics.Icmp6OutMsgs++;
+	ICMP6_INC_STATS(Icmp6OutRedirects);
+	ICMP6_INC_STATS(Icmp6OutMsgs);
 }
 
 static __inline__ struct neighbour *
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/proc.c linux/net/ipv6/proc.c
--- v2.3.38/linux/net/ipv6/proc.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv6/proc.c	Sat Jan  8 21:36:21 2000
@@ -7,7 +7,7 @@
  *		PROC file system.  This is very similar to the IPv4 version,
  *		except it reports the sockets in the INET6 address family.
  *
- * Version:	$Id: proc.c,v 1.12 1999/12/15 22:39:48 davem Exp $
+ * Version:	$Id: proc.c,v 1.13 2000/01/09 02:19:55 davem Exp $
  *
  * Authors:	David S. Miller (davem@caip.rutgers.edu)
  *
@@ -26,15 +26,26 @@
 #include <net/transp_v6.h>
 #include <net/ipv6.h>
 
-int afinet6_get_info(char *buffer, char **start, off_t offset, int length)
+static int fold_prot_inuse(struct proto *proto)
+{
+	int res = 0;
+	int cpu;
+
+	for (cpu=0; cpu<smp_num_cpus; cpu++)
+		res += proto->stats[cpu].inuse;
+
+	return res;
+}
+
+int afinet6_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
 {
 	int len = 0;
-	len += sprintf(buffer+len, "TCP6: inuse %d highest %d\n",
-		       tcpv6_prot.inuse, tcpv6_prot.highestinuse);
-	len += sprintf(buffer+len, "UDP6: inuse %d highest %d\n",
-		       udpv6_prot.inuse, udpv6_prot.highestinuse);
-	len += sprintf(buffer+len, "RAW6: inuse %d highest %d\n",
-		       rawv6_prot.inuse, rawv6_prot.highestinuse);
+	len += sprintf(buffer+len, "TCP6: inuse %d\n",
+		       fold_prot_inuse(&tcpv6_prot));
+	len += sprintf(buffer+len, "UDP6: inuse %d\n",
+		       fold_prot_inuse(&udpv6_prot));
+	len += sprintf(buffer+len, "RAW6: inuse %d\n",
+		       fold_prot_inuse(&rawv6_prot));
 	*start = buffer + offset;
 	len -= offset;
 	if(len > length)
@@ -47,9 +58,10 @@
 {
 	char *name;
 	unsigned long *ptr;
+	int   mibsize;
 } snmp6_list[] = {
 /* ipv6 mib according to draft-ietf-ipngwg-ipv6-mib-04 */
-#define SNMP6_GEN(x) { #x , &ipv6_statistics.x }
+#define SNMP6_GEN(x) { #x , &ipv6_statistics[0].x, sizeof(struct ipv6_mib)/sizeof(unsigned long) }
 	SNMP6_GEN(Ip6InReceives),
 	SNMP6_GEN(Ip6InHdrErrors),
 	SNMP6_GEN(Ip6InTooBigErrors),
@@ -83,7 +95,7 @@
 		OutRouterAdvertisements too.
 		OutGroupMembQueries too.
  */
-#define SNMP6_GEN(x) { #x , &icmpv6_statistics.x }
+#define SNMP6_GEN(x) { #x , &icmpv6_statistics[0].x, sizeof(struct icmpv6_mib)/sizeof(unsigned long) }
 	SNMP6_GEN(Icmp6InMsgs),
 	SNMP6_GEN(Icmp6InErrors),
 	SNMP6_GEN(Icmp6InDestUnreachs),
@@ -113,7 +125,7 @@
 	SNMP6_GEN(Icmp6OutGroupMembResponses),
 	SNMP6_GEN(Icmp6OutGroupMembReductions),
 #undef SNMP6_GEN
-#define SNMP6_GEN(x) { "Udp6" #x , &udp_stats_in6.Udp##x }
+#define SNMP6_GEN(x) { "Udp6" #x , &udp_stats_in6[0].Udp##x, sizeof(struct udp_mib)/sizeof(unsigned long) }
 	SNMP6_GEN(InDatagrams),
 	SNMP6_GEN(NoPorts),
 	SNMP6_GEN(InErrors),
@@ -121,6 +133,16 @@
 #undef SNMP6_GEN
 };
 
+static unsigned long fold_field(unsigned long *ptr, int size)
+{
+	unsigned long res = 0;
+	int i;
+
+	for (i=0; i<smp_num_cpus; i++)
+		res += ptr[i*size];
+
+	return res;
+}
 
 int afinet6_get_snmp(char *buffer, char **start, off_t offset, int length)
 {
@@ -129,7 +151,7 @@
 
 	for (i=0; i<sizeof(snmp6_list)/sizeof(snmp6_list[0]); i++)
 		len += sprintf(buffer+len, "%-32s\t%ld\n", snmp6_list[i].name,
-			       *(snmp6_list[i].ptr));
+			       fold_field(snmp6_list[i].ptr, snmp6_list[i].mibsize));
 
 	len -= offset;
 
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.3.38/linux/net/ipv6/raw.c	Wed Dec 29 13:13:21 1999
+++ linux/net/ipv6/raw.c	Sat Jan  8 21:36:21 2000
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/raw.c
  *
- *	$Id: raw.c,v 1.30 1999/12/15 22:39:51 davem Exp $
+ *	$Id: raw.c,v 1.31 2000/01/09 02:19: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
@@ -53,9 +53,7 @@
 		(*skp)->pprev = &sk->next;
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
  	sock_hold(sk);
  	write_unlock_bh(&raw_v6_lock);
 }
@@ -68,7 +66,7 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
-		sk->prot->inuse--;
+		sock_prot_dec_use(sk->prot);
 		__sock_put(sk);
 	}
 	write_unlock_bh(&raw_v6_lock);
@@ -259,12 +257,12 @@
 {
 	/* Charge it to the socket. */
 	if (sock_queue_rcv_skb(sk,skb)<0) {
-		ipv6_statistics.Ip6InDiscards++;
+		IP6_INC_STATS_BH(Ip6InDiscards);
 		kfree_skb(skb);
 		return 0;
 	}
 
-	ipv6_statistics.Ip6InDelivers++;
+	IP6_INC_STATS_BH(Ip6InDelivers);
 	return 0;
 }
 
@@ -785,6 +783,4 @@
 	128,				/* max_header */
 	0,				/* retransmits */
 	"RAW",				/* name */
-	0,				/* inuse */
-	0				/* highestinuse */
 };
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/reassembly.c linux/net/ipv6/reassembly.c
--- v2.3.38/linux/net/ipv6/reassembly.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipv6/reassembly.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: reassembly.c,v 1.15 1999/08/20 11:06:27 davem Exp $
+ *	$Id: reassembly.c,v 1.16 2000/01/09 02:19:51 davem Exp $
  *
  *	Based on: net/ipv4/ip_fragment.c
  *
@@ -135,7 +135,7 @@
 
 	spin_lock(&ip6_frag_lock);
 	while ((fq = ipv6_frag_queue.next) != &ipv6_frag_queue) {
-		ipv6_statistics.Ip6ReasmFails++;
+		IP6_INC_STATS_BH(Ip6ReasmFails);
 		fq_free(fq);
 		if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh) {
 			spin_unlock(&ip6_frag_lock);
@@ -158,7 +158,7 @@
 
 	hdr = skb->nh.ipv6h;
 
-	ipv6_statistics.Ip6ReasmReqds++;
+	IP6_INC_STATS_BH(Ip6ReasmReqds);
 
 	/* Jumbo payload inhibits frag. header */
 	if (hdr->payload_len==0) {
@@ -228,8 +228,8 @@
 
 	frag = fq->fragments;
 
-	ipv6_statistics.Ip6ReasmTimeout++;
-	ipv6_statistics.Ip6ReasmFails++;
+	IP6_INC_STATS_BH(Ip6ReasmTimeout);
+	IP6_INC_STATS_BH(Ip6ReasmFails);
 
 	if (frag == NULL) {
 		spin_unlock(&ip6_frag_lock);
@@ -272,7 +272,7 @@
 						GFP_ATOMIC);
 
 	if (fq == NULL) {
-		ipv6_statistics.Ip6ReasmFails++;
+		IP6_INC_STATS_BH(Ip6ReasmFails);
 		kfree_skb(skb);
 		return;
 	}
@@ -450,7 +450,7 @@
 	if (payload_len > 65535) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "reasm_frag: payload len = %d\n", payload_len);
-		ipv6_statistics.Ip6ReasmFails++;
+		IP6_INC_STATS_BH(Ip6ReasmFails);
 		fq_free(fq);
 		return NULL;
 	}
@@ -458,7 +458,7 @@
 	if ((skb = dev_alloc_skb(sizeof(struct ipv6hdr) + payload_len))==NULL) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "reasm_frag: no memory for reassembly\n");
-		ipv6_statistics.Ip6ReasmFails++;
+		IP6_INC_STATS_BH(Ip6ReasmFails);
 		fq_free(fq);
 		return NULL;
 	}
@@ -505,6 +505,6 @@
 
 	frag_kfree_s(fq, sizeof(*fq));
 
-	ipv6_statistics.Ip6ReasmOKs++;
+	IP6_INC_STATS_BH(Ip6ReasmOKs);
 	return nhptr;
 }
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/route.c linux/net/ipv6/route.c
--- v2.3.38/linux/net/ipv6/route.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv6/route.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: route.c,v 1.43 2000/01/06 00:42:08 davem Exp $
+ *	$Id: route.c,v 1.44 2000/01/09 02:19: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
@@ -1176,7 +1176,7 @@
 
 int ip6_pkt_discard(struct sk_buff *skb)
 {
-	ipv6_statistics.Ip6OutNoRoutes++;
+	IP6_INC_STATS(Ip6OutNoRoutes);
 	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
 	kfree_skb(skb);
 	return 0;
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.38/linux/net/ipv6/tcp_ipv6.c	Thu Jan  6 12:57:48 2000
+++ linux/net/ipv6/tcp_ipv6.c	Sat Jan  8 21:36:21 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.115 2000/01/06 00:42:09 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.116 2000/01/09 02:19:52 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -219,9 +219,7 @@
 		(*skp)->pprev = &sk->next;
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
 	write_unlock(lock);
 }
 
@@ -410,9 +408,7 @@
 
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
 	write_unlock_bh(&head->lock);
 
 #ifdef CONFIG_TCP_TW_RECYCLE
@@ -692,7 +688,7 @@
 	sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex);
 
 	if (sk == NULL) {
-		icmpv6_statistics.Icmp6InErrors++;
+		ICMP6_INC_STATS_BH(Icmp6InErrors);
 		return;
 	}
 
@@ -703,12 +699,12 @@
 
 	bh_lock_sock(sk);
 	if (sk->lock.users)
-		net_statistics.LockDroppedIcmps++;
+		NET_INC_STATS_BH(LockDroppedIcmps);
 
 	tp = &sk->tp_pinfo.af_tcp;
 	seq = ntohl(th->seq); 
 	if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) {
-		net_statistics.OutOfWindowIcmps++;
+		NET_INC_STATS_BH(OutOfWindowIcmps);
 		goto out;
 	}
 
@@ -781,12 +777,12 @@
 
 			tp = &sk->tp_pinfo.af_tcp;
 			if (!between(seq, tp->snd_una, tp->snd_nxt)) {
-				net_statistics.OutOfWindowIcmps++;
+				NET_INC_STATS_BH(OutOfWindowIcmps);
 				goto out;
 			}
 		} else {
 			if (seq != req->snt_isn) {
-				net_statistics.OutOfWindowIcmps++;
+				NET_INC_STATS_BH(OutOfWindowIcmps);
 				goto out;
 			}
 
@@ -802,7 +798,7 @@
 	case TCP_SYN_RECV:  /* Cannot happen.
 			       It can, it SYNs are crossed. --ANK */ 
 		if (sk->lock.users == 0) {
-			tcp_statistics.TcpAttemptFails++;
+			TCP_INC_STATS_BH(TcpAttemptFails);
 			sk->err = err;
 			sk->error_report(sk);		/* Wake people up to see the error (see connect in sock.c) */
 
@@ -996,7 +992,7 @@
 	return 0;
 
 drop:
-	tcp_statistics.TcpAttemptFails++;
+	TCP_INC_STATS_BH(TcpAttemptFails);
 	return 0; /* don't send reset */
 }
 
@@ -1238,8 +1234,8 @@
 
 	if (buff->dst->error == 0) {
 		ip6_xmit(NULL, buff, &fl, NULL);
-		tcp_statistics.TcpOutSegs++;
-		tcp_statistics.TcpOutRsts++;
+		TCP_INC_STATS_BH(TcpOutSegs);
+		TCP_INC_STATS_BH(TcpOutRsts);
 		return;
 	}
 
@@ -1304,7 +1300,7 @@
 
 	if (buff->dst->error == 0) {
 		ip6_xmit(NULL, buff, &fl, NULL);
-		tcp_statistics.TcpOutSegs++;
+		TCP_INC_STATS_BH(TcpOutSegs);
 		return;
 	}
 
@@ -1437,7 +1433,7 @@
 	 *	is currently called with bh processing disabled.
 	 */
 
-  	ipv6_statistics.Ip6InDelivers++;
+  	IP6_INC_STATS_BH(Ip6InDelivers);
 
 	/* 
 	 * This doesn't check if the socket has enough room for the packet.
@@ -1526,7 +1522,7 @@
 	kfree_skb(skb);
 	return 0;
 csum_err:
-	tcp_statistics.TcpInErrs++;
+	TCP_INC_STATS_BH(TcpInErrs);
 	goto discard;
 
 
@@ -1587,7 +1583,7 @@
 	 *	Count it even if it's bad.
 	 */
 
-	tcp_statistics.TcpInSegs++;
+	TCP_INC_STATS_BH(TcpInSegs);
 
 	if (len < sizeof(struct tcphdr))
 		goto bad_packet;
@@ -1624,7 +1620,7 @@
 no_tcp_socket:
 	if (tcp_v6_csum_verify(skb)) {
 bad_packet:
-		tcp_statistics.TcpInErrs++;
+		TCP_INC_STATS_BH(TcpInErrs);
 	} else {
 		tcp_v6_send_reset(skb);
 	}
@@ -1644,7 +1640,7 @@
 
 do_time_wait:
 	if (tcp_v6_csum_verify(skb)) {
-		tcp_statistics.TcpInErrs++;
+		TCP_INC_STATS_BH(TcpInErrs);
 		sock_put(sk);
 		goto discard_it;
 	}
@@ -2124,8 +2120,6 @@
 	128,				/* max_header */
 	0,				/* retransmits */
 	"TCPv6",			/* name */
-	0,				/* inuse */
-	0				/* highestinuse */
 };
 
 static struct inet6_protocol tcpv6_protocol =
diff -u --recursive --new-file v2.3.38/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.3.38/linux/net/ipv6/udp.c	Fri Jan  7 19:13:23 2000
+++ linux/net/ipv6/udp.c	Sat Jan  8 21:36:21 2000
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.47 2000/01/05 21:27:54 davem Exp $
+ *	$Id: udp.c,v 1.48 2000/01/09 02:19:53 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -45,7 +45,7 @@
 
 #include <net/checksum.h>
 
-struct udp_mib udp_stats_in6;
+struct udp_mib udp_stats_in6[NR_CPUS*2];
 
 /* Grrr, addr_type already calculated by caller, but I don't want
  * to add some silly "cookie" argument to this method just for that.
@@ -130,9 +130,7 @@
 		(*skp)->pprev = &sk->next;
 	*skp = sk;
 	sk->pprev = skp;
-	sk->prot->inuse++;
-	if(sk->prot->highestinuse < sk->prot->inuse)
-		sk->prot->highestinuse = sk->prot->inuse;
+	sock_prot_inc_use(sk->prot);
  	sock_hold(sk);
  	write_unlock_bh(&udp_hash_lock);
 }
@@ -145,7 +143,7 @@
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
-		sk->prot->inuse--;
+		sock_prot_dec_use(sk->prot);
 		__sock_put(sk);
 	}
 	write_unlock_bh(&udp_hash_lock);
@@ -494,8 +492,8 @@
 #if defined(CONFIG_FILTER) && defined(CONFIG_UDP_DELAY_CSUM)
 	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
 		if ((unsigned short)csum_fold(csum_partial(skb->h.raw, skb->len, skb->csum))) {
-			udp_stats_in6.UdpInErrors++;
-			ipv6_statistics.Ip6InDiscards++;
+			UDP6_INC_STATS_BH(UdpInErrors);
+			IP6_INC_STATS_BH(Ip6InDiscards);
 			kfree_skb(skb);
 			return 0;
 		}
@@ -503,13 +501,13 @@
 	}
 #endif
 	if (sock_queue_rcv_skb(sk,skb)<0) {
-		udp_stats_in6.UdpInErrors++;
-		ipv6_statistics.Ip6InDiscards++;
+		UDP6_INC_STATS_BH(UdpInErrors);
+		IP6_INC_STATS_BH(Ip6InDiscards);
 		kfree_skb(skb);
 		return 0;
 	}
-  	ipv6_statistics.Ip6InDelivers++;
-	udp_stats_in6.UdpInDatagrams++;
+  	IP6_INC_STATS_BH(Ip6InDelivers);
+	UDP6_INC_STATS_BH(UdpInDatagrams);
 	return 0;
 }
 
@@ -607,7 +605,7 @@
 	if (ulen > len || len < sizeof(*uh)) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "UDP: short packet: %d/%ld\n", ulen, len);
-		udp_stats_in6.UdpInErrors++;
+		UDP6_INC_STATS_BH(UdpInErrors);
 		kfree_skb(skb);
 		return(0);
 	}
@@ -667,7 +665,7 @@
 		    (unsigned short)csum_fold(csum_partial((char*)uh, len, skb->csum)))
 			goto discard;
 #endif
-		udp_stats_in6.UdpNoPorts++;
+		UDP6_INC_STATS_BH(UdpNoPorts);
 
 		icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev);
 
@@ -676,7 +674,7 @@
 	}
 	if (0/*sk->user_callback &&
 	    sk->user_callback(sk->user_data, skb) == 0*/) {
-		udp_stats_in6.UdpInDatagrams++;
+		UDP6_INC_STATS_BH(UdpInDatagrams);
 		sock_put(sk);
 		return(0);
 	}
@@ -688,7 +686,7 @@
 	return(0);
 	
 discard:
-	udp_stats_in6.UdpInErrors++;
+	UDP6_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);	
 }
@@ -885,7 +883,7 @@
 	if (err < 0)
 		return err;
 
-	udp_stats_in6.UdpOutDatagrams++;
+	UDP6_INC_STATS_USER(UdpOutDatagrams);
 	return ulen;
 }
 
@@ -1002,8 +1000,6 @@
 	128,				/* max_header */
 	0,				/* retransmits */
 	"UDP",				/* name */
-	0,				/* inuse */
-	0				/* highestinuse */
 };
 
 void __init udpv6_init(void)
diff -u --recursive --new-file v2.3.38/linux/net/khttpd/security.c linux/net/khttpd/security.c
--- v2.3.38/linux/net/khttpd/security.c	Thu Aug 26 13:05:46 1999
+++ linux/net/khttpd/security.c	Mon Jan 10 14:05:33 2000
@@ -131,7 +131,7 @@
 	
 	if ((permission & sysctl_khttpd_permreq)==0)
 	{
-		if (filp!=NULL);
+		if (filp!=NULL)
 			fput(filp);
 		filp=NULL;
 		return NULL;
diff -u --recursive --new-file v2.3.38/linux/net/netsyms.c linux/net/netsyms.c
--- v2.3.38/linux/net/netsyms.c	Thu Jan  6 12:57:48 2000
+++ linux/net/netsyms.c	Sat Jan  8 21:36:21 2000
@@ -306,6 +306,7 @@
 EXPORT_SYMBOL(ip_queue_xmit);
 EXPORT_SYMBOL(memcpy_fromiovecend);
 EXPORT_SYMBOL(csum_partial_copy_fromiovecend);
+EXPORT_SYMBOL(copy_and_csum_toiovec);
 EXPORT_SYMBOL(tcp_keepalive_timer);
 EXPORT_SYMBOL(tcp_v4_lookup_listener);
 /* UDP/TCP exported functions for TCPv6 */
diff -u --recursive --new-file v2.3.38/linux/net/sched/cls_tcindex.c linux/net/sched/cls_tcindex.c
--- v2.3.38/linux/net/sched/cls_tcindex.c	Fri Jan  7 19:13:23 2000
+++ linux/net/sched/cls_tcindex.c	Sat Jan  8 21:36:48 2000
@@ -4,6 +4,7 @@
  * Written 1998,1999 by Werner Almesberger, EPFL ICA
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
