diff -u --recursive --new-file v2.3.17/linux/CREDITS linux/CREDITS
--- v2.3.17/linux/CREDITS	Tue Aug 31 17:29:12 1999
+++ linux/CREDITS	Wed Sep  8 11:21:19 1999
@@ -1031,16 +1031,6 @@
 S: 80-283 Gdansk
 S: Poland
 
-N: Dave Jones
-E: dave@powertweak.com
-W: http://linux.powertweak.com
-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: Wales, United Kingdom
-
 N: Bernhard Kaindl
 E: bkaindl@netway.at
 E: edv@bartelt.via.at
diff -u --recursive --new-file v2.3.17/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.17/linux/Documentation/Configure.help	Tue Sep  7 12:14:05 1999
+++ linux/Documentation/Configure.help	Wed Sep  8 11:14:31 1999
@@ -3578,8 +3578,8 @@
 Asynchronous Transfer Mode (ATM)
 CONFIG_ATM
   Kernel support for ATM. Note that you need a set of user-space programs
-  to actually make use of ATM. See http://lrcwww.epfl.ch/linux-atm/ for
-  further details.
+  to actually make use of ATM. See Documentation/atm.txt for further
+  details.
 
 Classical IP over ATM
 CONFIG_ATM_CLIP
@@ -3609,12 +3609,6 @@
   subnetwork boundaries. These shortcut connections bypass routers
   enhancing overall network performance.
 
-
-Application REQUested IP over ATM
-CONFIG_AREQUIPA
-  Arequipa is a mechanism to create ATM connections under application
-  control for IP traffic. See RFC2170 for details.
-
 ATM over TCP
 CONFIG_ATM_TCP
   ATM over TCP driver. Useful mainly for development and for experiments.
@@ -11283,6 +11277,17 @@
   which can be inserted in and removed from the running kernel
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
+
+Direct Rendering Manager (XFree86 DRI support)
+CONFIG_DRM
+  Kernel-level support for the Direct Rendering Infrastructure (DRI)
+  introduced in XFree86 4.x.  These modules provide support for
+  synchronization, security, and DMA transfers.  Select the module that
+  provides support for your graphics card.
+
+3dlabs GMX 2000 Direct Rendering Driver (XFree86 DRI support)
+CONFIG_DRM_GAMMA
+  Choose M here if you have a 3dlabs GMX 2000 graphics card.
 
 AIMSlab RadioTrack (aka RadioReveal) support
 CONFIG_RADIO_RTRACK
diff -u --recursive --new-file v2.3.17/linux/Documentation/atm.txt linux/Documentation/atm.txt
--- v2.3.17/linux/Documentation/atm.txt	Thu Aug 26 13:05:34 1999
+++ linux/Documentation/atm.txt	Wed Sep  8 11:14:31 1999
@@ -2,3 +2,7 @@
 several user-mode programs are required to assist the kernel. These
 programs and related material can be found via the ATM on Linux Web
 page at http://icawww1.epfl.ch/linux-atm/
+
+If you encounter problems with ATM, please report them on the ATM
+on Linux mailing list. Subscription information, archives, etc.,
+can be found on http://icawww1.epfl.ch/linux-atm/
diff -u --recursive --new-file v2.3.17/linux/Documentation/fb/clgenfb.txt linux/Documentation/fb/clgenfb.txt
--- v2.3.17/linux/Documentation/fb/clgenfb.txt	Wed Aug 18 10:10:06 1999
+++ linux/Documentation/fb/clgenfb.txt	Fri Sep 10 11:12:16 1999
@@ -13,9 +13,10 @@
 	Piccolo
 	Picasso
 	Spectrum
-	Picasso4 (GD-5446)
 	Alpine (GD-543x/4x)
+	Picasso4 (GD-5446)
 	GD-5480
+	Laguna (GD-546x)
 
 Bus's supported:
 	PCI
@@ -41,19 +42,51 @@
 
 
 
+Version 1.9.4.4
+---------------
+* Preliminary Laguna support
+* Overhaul color register routines.  Shifts are now based on offset
+  values in var.cmap, so as long as those are correctly set for PReP
+  things should work (knock on wood).
+* Associated with the above, console colors are now obtained from a LUT
+  called 'palette' instead of from the VGA registers.  This code was
+  modeled after that in atyfb and matroxfb.
+* Code cleanup, add comments.
+* Overhaul SR07 handling.
+* Bug fixes.
+
+
+Version 1.9.4.3
+---------------
+* Correctly set default startup video mode.
+* Do not override ram size setting.  Define
+  CLGEN_USE_HARDCODED_RAM_SETTINGS if you _do_ want to override the RAM
+  setting.
+* Compile fixes related to new 2.3.x IORESOURCE_IO[PORT] symbol changes.
+* Use new 2.3.x resource allocation.
+* Some code cleanup.
+
+
+Version 1.9.4.2
+---------------
+* Casting fixes.
+* Assertions no longer cause an oops on purpose.
+* Bug fixes.
+
+
 Version 1.9.4.1
 ---------------
-Add compatibility support.  Now requires a 2.1.x, 2.2.x or 2.3.x kernel.
+* Add compatibility support.  Now requires a 2.1.x, 2.2.x or 2.3.x kernel.
 
 
 Version 1.9.4
 -------------
-Several enhancements, smaller memory footprint, a few bugfixes.
-Requires kernel 2.3.14-pre1 or later.
+* Several enhancements, smaller memory footprint, a few bugfixes.
+* Requires kernel 2.3.14-pre1 or later.
 
 
 Version 1.9.3
 -------------
-Bundled with kernel 2.3.14-pre1 or later.
+* Bundled with kernel 2.3.14-pre1 or later.
 
 
diff -u --recursive --new-file v2.3.17/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.3.17/linux/Documentation/ioctl-number.txt	Tue Aug 31 17:29:12 1999
+++ linux/Documentation/ioctl-number.txt	Wed Sep  8 11:14:50 1999
@@ -1,37 +1,41 @@
 Ioctl Numbers
-18 Feb 1998
-Michael Chastain
+2 September 1999
+Michael Elizabeth Chastain
 <mec@shout.net>
 
 If you are adding new ioctl's to the kernel, you should use the _IO
 macros defined in <linux/ioctl.h>:
 
     _IO    an ioctl with no parameters
-    _IOW   an ioctl with write parameters (from user's point of view)
-    _IOR   an ioctl with read parameters (from user's point of view)
+    _IOW   an ioctl with write parameters (copy_from_user)
+    _IOR   an ioctl with read parameters  (copy_to_user)
     _IOWR  an ioctl with both write and read parameters.
 
-'Write' and 'read' are from the user's point of view.  This is like the
-system calls 'write' and 'read'.  For example, a SET_FOO ioctl would be
-_IOW, although the kernel would actually read data from user space; a
-GET_FOO ioctl would be _IOR, although the kernel would actually write
+'Write' and 'read' are from the user's point of view, just like the
+system calls 'write' and 'read'.  For example, a SET_FOO ioctl would
+be _IOW, although the kernel would actually read data from user space;
+a GET_FOO ioctl would be _IOR, although the kernel would actually write
 data to user space.
 
 The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter
-or number from the table below.  If you are writing a driver for a new
-device and need a letter, pick an unused letter.  You can register the
-letter by patching this file and submitting the patch to Linus Torvalds.
-Or you can e-mail me at <mec@shout.net> and I'll register one for you.
+or number from the table below.  Because of the large number of drivers,
+many drivers share a partial letter with other drivers.
+
+If you are writing a driver for a new device and need a letter, pick an
+unused block with enough room for expansion: 32 to 256 ioctl commands.
+You can register the block by patching this file and submitting the
+patch to Linus Torvalds.  Or you can e-mail me at <mec@shout.net> and
+I'll register one for you.
 
 The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
 to distinguish ioctls from each other.  The third argument is the size
 of the structure going into the kernel or coming out of the kernel.
 
-Some devices use their major number as the identifier; this is not
-recommended.  Some devices are even more irregular and don't follow
-the convention at all.
+Some devices use their major number as the identifier; this is OK, as
+long as it is unique.  Some devices are irregular and don't follow any
+convention at all.
 
-Following the convention is good because:
+Following this convention is good because:
 
 (1) Keeping the ioctl's globally unique helps error checking:
     if a program calls an ioctl on the wrong device, it will get an
@@ -44,92 +48,124 @@
     numbers are unique.
 
 (4) People looking for ioctls can grep for them more easily when
-    the convention is used to define the ioctl numbers.
+    this convention is used to define the ioctl numbers.
 
 (5) When following the convention, the driver code can use generic
-    code to call verify_area to validate parameters.
+    code to copy the parameters between user and kernel space.
 
-This table lists ioctls visible from user land for Linux/i386.  It is
-current to Linux 2.1.15.
+This table lists ioctls visible from user land for Linux/i386.  It contains
+most drivers up to 2.3.14, but I know I am missing some.
 
 Code	Seq#	Include File		Comments
 ========================================================
-0x00	01-02	linux/fs.h		conflict!
-0x00	01-04	scsi/scsi_ioctl.h	conflict!
+0x00	00-1F	linux/fs.h		conflict!
+0x00	00-1F	scsi/scsi_ioctl.h	conflict!
+0x00	00-1F	linux/fb.h		conflict!
+0x00	00-1F	linux/wavefront.h	conflict!
 0x02	all	linux/fd.h
 0x03	all	linux/hdreg.h
 0x04	all	linux/umsdos_fs.h
 0x06	all	linux/lp.h
 0x09	all	linux/md.h
 0x12	all	linux/fs.h
-0x20	all	linux/cm206.h
+		linux/blkpg.h
+0x20	all	drivers/cdrom/cm206.h
 0x22	all	scsi/sg.h
-'A'	all	linux/apm_bios.h
+'1'	00-1F	<linux/timepps.h>	PPS kit from Ulrich Windl
+					<ftp://ftp.de.kernel.org/pub/linux/daemons/ntp/PPS/>
+'8'	all				SNP8023 advanced NIC card
+					<mailto:mcr@solidum.com>
+'A'	00-1F	linux/apm_bios.h
+'B'	C0-FF				advanced bbus
+					<mailto:maassen@uni-freiburg.de>
 'C'	all	linux/soundcard.h
 'F'	all	linux/fb.h
 'I'	all	linux/isdn.h
+'J'	00-1F	drivers/scsi/gdth_ioctl.h
 'K'	all	linux/kd.h
-'L'	all	linux/loop.h
-'M'	all	linux/soundcard.h
+'L'	00-1F	linux/loop.h
+'L'	E0-FF	linux/ppdd.h		encrypted disk device driver
+					<http://linux01.gwdg.de/~alatham/ppdd.html>
+'M'	all	linux/soundcard.h	conflict!
+'M'	00-1F	linux/isicom.h		conflict!
 'P'	all	linux/soundcard.h
 'Q'	all	linux/soundcard.h
-'R'	all	linux/random.h
-'S'	00-7F	linux/cdrom.h
-'S'	80-81	scsi/scsi_ioctl.h
-'S'	82-FF	scsi/scsi.h
+'R'	00-1F	linux/random.h
+'S'	all	linux/cdrom.h		conflict!
+'S'	80-81	scsi/scsi_ioctl.h	conflict!
+'S'	82-FF	scsi/scsi.h		conflict!
 'T'	all	linux/soundcard.h	conflict!
 'T'	all	asm-i386/ioctls.h	conflict!
-'U'     all     linux/drivers/usb/usb.h
+'U'	all	linux/drivers/usb/usb.h
 'V'	all	linux/vt.h
-'W'	00-1F	linux/router.h		conflict [Please reallocate]
-'W'	00-1F	linux/watchdog.h
-'W'	20-27	linux/octal-relay.h	in development
-'W'	28-2F	linux/iso16-relay.h	in development
+'W'	00-1F	linux/watchdog.h	conflict!
+'W'	00-1F	linux/wanrouter.h	conflict!
 'Y'	all	linux/cyclades.h
-'a'	all	various, see http://lrcwww.epfl.ch/linux-atm/magic.html
-'b'	00-FF	bit3 vme host bridge	in development:
+'a'	all				ATM on linux
+					<http://lrcwww.epfl.ch/linux-atm/magic.html>
+'b'	00-FF				bit3 vme host bridge
 					<mailto:natalia@nikhefk.nikhef.nl>
-'c'	all	linux/comstats.h
-'f'	all	linux/ext2_fs.h
+'c'	00-7F	linux/comstats.h	conflict!
+'c'	00-7F	linux/coda.h		conflict!
+'d'	00-1F	linux/devfs_fs.h	conflict!
+'d'	00-DF	linux/video_decoder.h	conflict!
+'d'	F0-FF	linux/digi1.h
+'e'	all	linux/digi1.h		conflict!
+'e'	00-1F	linux/video_encoder.h	conflict!
+'e'	00-1F	net/irda/irtty.h	conflict!
+'f'	00-1F	linux/ext2_fs.h
+'i'	00-3F	linux/i2o.h
 'j'	00-3F	linux/joystick.h
-'k'	all	asm-sparc/kbio.h, asm-sparc64/kbio.h
-'l'	00-3F	linux/tcfs_fs.h		in development:
+'k'	all	asm-sparc/kbio.h
+		asm-sparc64/kbio.h
+'l'	00-3F	linux/tcfs_fs.h		transparent cryptographic file system
 					<http://mikonos.dia.unisa.it/tcfs>
 'm'	all	linux/mtio.h		conflict!
 'm'	all	linux/soundcard.h	conflict!
+'m'	all	linux/synclink.h	conflict!
+'m'	00-1F	net/irda/irmod.h	conflict!
 'n'	all	linux/ncp_fs.h
 'p'	00-3F	linux/mc146818rtc.h
 'p'	40-7F	linux/nvram.h
-'p'	80-9F	user-space parport	in development:
-					<tim@cyberelk.demon.co.uk>
-'r'	all	linux/msdos_fs.h
+'p'	80-9F				user-space parport
+					<mailto:tim@cyberelk.demon.co.uk>
+'q'	00-1F	linux/videotext.h	conflict!
+'q'	80-FF				Internet PhoneJACK, Internet LineJACK
+					<http://www.quicknet.net>
+'r'	00-1F	linux/msdos_fs.h
 's'	all	linux/cdk.h
 't'	00-7F	linux/if_ppp.h
 't'	80-8F	linux/isdn_ppp.h
-'u'	all	linux/smb_fs.h
-'v'	all	linux/ext2_fs.h
-'w'	all	CERN SCI driver		in development
-'z'	00-3F	CAN bus card		in development:
+'u'	00-1F	linux/smb_fs.h
+'v'	00-1F	linux/ext2_fs.h		conflict!
+'v'	all	linux/videodev.h	conflict!
+'w'	all				CERN SCI driver
+'z'	00-3F				CAN bus card
 					<mailto:hdstich@connectu.ulm.circular.de>
-'z'	40-7F	CAN bas card		in development:
+'z'	40-7F				CAN bus card
 					<mailto:oe@port.de>
-0x89	00-0F	asm-i386/sockios.h
-0x89	10-DF	linux/sockios.h
+0x80	00-1F	linux/fb.h
+0x89	00-06	asm-i386/sockios.h
+0x89	0B-DF	linux/sockios.h
 0x89	E0-EF	linux/sockios.h		SIOCPROTOPRIVATE range
 0x89	F0-FF	linux/sockios.h		SIOCDEVPRIVATE range
 0x8B	all	linux/wireless.h
-0x8C	00-3F	WiNRADiO driver		in development:
+0x8C	00-3F				WiNRADiO driver
 					<http://www.proximity.com.au/~brian/winradio/>
-0x90	00	linux/sbpcd.h
+0x90	00	drivers/cdrom/sbpcd.h
 0x93	60-7F	linux/auto_fs.h
-0x99	00-0F	537-Addinboard driver	in development:
-					<mailto:b.kohl@ipn-b.comlink.apc.org>
-0xA0	all	Small Device Project	in development:
-					<mailto:khollis@northwest.com>
+0x99	00-0F				537-Addinboard driver
+					<mailto:buk@buks.ipn.de>
+0xA0	all	linux/sdp/sdp.h		Industrial Device Project
+					<mailto:kenji@bitgate.com>
+0xA3	00-1F	Philips SAA7146 dirver	in development:
+					<mailto:Andreas.Beckmann@hamburg.sc.philips.com>
 0xA3	80-8F	Port ACL		in development:
 					<mailto:tlewis@mindspring.com>
-0xA3	90-9F	DoubleTalk driver	in development:
-					<mailto:jrv@vanzandt.mv.com>
-0xAB	00-06	Network block device
+0xA3	90-9F	linux/dtlk.h
+0xAB	00-1F	linux/nbd.h
+0xAC	00-1F	linux/raw.h
 0xAD	00	Netfilter device	in development:
 					<mailto:rusty@rustcorp.com.au>	
+0xB0	all	RATIO devices		in development:
+					<mailto:vgo@ratio.de>
diff -u --recursive --new-file v2.3.17/linux/Makefile linux/Makefile
--- v2.3.17/linux/Makefile	Tue Sep  7 12:14:05 1999
+++ linux/Makefile	Thu Sep  9 17:14:38 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 17
+SUBLEVEL = 18
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -148,6 +148,7 @@
 
 ifdef CONFIG_PCMCIA
 DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o
+DRIVERS := $(DRIVERS) drivers/net/pcmcia/pcmcia_net.o
 endif
 
 ifdef CONFIG_DIO
diff -u --recursive --new-file v2.3.17/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.3.17/linux/arch/alpha/kernel/smp.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/smp.c	Wed Sep  8 11:59:00 1999
@@ -13,6 +13,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include <asm/hwrpb.h>
 #include <asm/ptrace.h>
@@ -22,7 +23,6 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
-#include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/arch/arm/kernel/dma-dummy.c linux/arch/arm/kernel/dma-dummy.c
--- v2.3.17/linux/arch/arm/kernel/dma-dummy.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/dma-dummy.c	Wed Sep  8 11:59:00 1999
@@ -8,8 +8,7 @@
  */
 #include <linux/errno.h>
 #include <linux/init.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED;
 
diff -u --recursive --new-file v2.3.17/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c
--- v2.3.17/linux/arch/arm/kernel/dma.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/dma.c	Wed Sep  8 11:59:00 1999
@@ -19,13 +19,13 @@
 #include <linux/malloc.h>
 #include <linux/mman.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/page.h>
 #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/spinlock.h>
 
 
 /* A note on resource allocation:
diff -u --recursive --new-file v2.3.17/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c
--- v2.3.17/linux/arch/arm/kernel/leds-footbridge.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/leds-footbridge.c	Wed Sep  8 11:59:00 1999
@@ -21,10 +21,10 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware.h>
 #include <asm/leds.h>
-#include <asm/spinlock.h>
 #include <asm/system.h>
 
 #define LED_STATE_ENABLED	1
diff -u --recursive --new-file v2.3.17/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- v2.3.17/linux/arch/arm/kernel/traps.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/traps.c	Wed Sep  8 11:59:00 1999
@@ -16,11 +16,11 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/pgtable.h>
 
diff -u --recursive --new-file v2.3.17/linux/arch/arm/nwfpe/fpmodule.c linux/arch/arm/nwfpe/fpmodule.c
--- v2.3.17/linux/arch/arm/nwfpe/fpmodule.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/nwfpe/fpmodule.c	Wed Sep  8 11:59:00 1999
@@ -37,11 +37,11 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/pgtable.h>
 /* XXX */
diff -u --recursive --new-file v2.3.17/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.17/linux/arch/i386/defconfig	Tue Sep  7 12:14:06 1999
+++ linux/arch/i386/defconfig	Thu Sep  9 22:16:49 1999
@@ -257,6 +257,7 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
 # CONFIG_PPP is not set
@@ -279,6 +280,12 @@
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
+
+#
+# PCMCIA network devices
+#
+# CONFIG_PCMCIA_PCNET is not set
+CONFIG_PCMCIA_RAYCS=y
 
 #
 # Amateur Radio support
diff -u --recursive --new-file v2.3.17/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.3.17/linux/arch/i386/kernel/apm.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/i386/kernel/apm.c	Wed Sep  8 11:33:31 1999
@@ -983,40 +983,27 @@
 	}
 }
 
-/*
- * This is the APM thread main loop.
- */
-static void apm_mainloop(void)
+static void apm_event_handler(void)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	apm_enabled = 1;
+	static int pending_count = 0;
 
-	add_wait_queue(&apm_waitqueue, &wait);
-	for (;;) {
-		static int pending_count = 0;
+	if (((standbys_pending > 0) || (suspends_pending > 0))
+	    && (apm_bios_info.version > 0x100)
+	    && (pending_count-- <= 0)) {
 		int err;
+		pending_count = 4;
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(APM_CHECK_TIMEOUT);
-
-		if (((standbys_pending > 0) || (suspends_pending > 0))
-		    && (apm_bios_info.version > 0x100)
-		    && (pending_count-- <= 0)) {
-			pending_count = 4;
-
-			err = apm_set_power_state(APM_STATE_BUSY);
-			if (err)
-				apm_error("busy", err);
-		}
-
-		if (!(((standbys_pending > 0) || (suspends_pending > 0))
-		      && (apm_bios_info.version == 0x100)))
-			check_events();
+		err = apm_set_power_state(APM_STATE_BUSY);
+		if (err)
+			apm_error("busy", err);
 	}
+
+	if (!(((standbys_pending > 0) || (suspends_pending > 0))
+	      && (apm_bios_info.version == 0x100)))
+		check_events();
 }
 
-/* Called from cpu_idle, must make sure apm_enabled. */
-int apm_do_idle(void)
+static int apm_do_idle(void)
 {
 #ifdef CONFIG_APM_CPU_IDLE
 	u32	dummy;
@@ -1027,28 +1014,72 @@
 	if (apm_bios_call_simple(0x5305, 0, 0, &dummy))
 		return 0;
 
+#ifdef ALWAYS_CALL_BUSY
+	clock_slowed = 1;
+#else
 	clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+#endif
 	return 1;
 #else
 	return 0;
 #endif
 }
 
-/* Called from cpu_idle, must make sure apm_enabled. */
-void apm_do_busy(void)
+static void apm_do_busy(void)
 {
 #ifdef CONFIG_APM_CPU_IDLE
 	u32	dummy;
 
-	if (apm_enabled
-#ifndef ALWAYS_CALL_BUSY
-		&& clock_slowed
-#endif
-	) {
+	if (clock_slowed) {
 		(void) apm_bios_call_simple(0x5306, 0, 0, &dummy);
 		clock_slowed = 0;
 	}
 #endif
+}
+
+/*
+ * This is the APM thread main loop.
+ *
+ * Check whether we're the only running process to
+ * decide if we should just power down.
+ *
+ * Do this by checking the runqueue: if we're the
+ * only one, then the current process run_list will
+ * have both prev and next pointing to the same
+ * entry (the true idle process)
+ */
+#define system_idle() (current->run_list.next == current->run_list.prev)
+
+static void apm_mainloop(void)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	apm_enabled = 1;
+
+	add_wait_queue(&apm_waitqueue, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	for (;;) {
+		/* Nothing to do, just sleep for the timeout */
+		schedule_timeout(APM_CHECK_TIMEOUT);
+
+		/*
+		 * Ok, check all events, check for idle (and mark us sleeping
+		 * so as not to count towards the load average)..
+		 */
+		current->state = TASK_INTERRUPTIBLE;
+		apm_event_handler();
+		if (!system_idle())
+			continue;
+		if (apm_do_idle()) {
+			unsigned long start = jiffies;
+			do {
+				apm_do_idle();
+				if (jiffies - start > APM_CHECK_TIMEOUT)
+					break;
+			} while (system_idle());
+			apm_do_busy();
+			apm_event_handler();
+		}
+	}
 }
 
 static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func)
diff -u --recursive --new-file v2.3.17/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.3.17/linux/arch/i386/kernel/bios32.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/kernel/bios32.c	Wed Sep  8 12:21:35 1999
@@ -88,13 +88,13 @@
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/irq.h>
+#include <linux/spinlock.h>
 
 #include <asm/page.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/smp.h>
-#include <asm/spinlock.h>
 
 #undef DEBUG
 
@@ -760,36 +760,6 @@
 #endif
 
 /*
- * Assign new address to PCI resource.  We hope our resource information
- * is complete.  On the PC, we don't re-assign resources unless we are
- * forced to do so.
- *
- * Expects start=0, end=size-1, flags=resource type.
- */
-
-int __init pcibios_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;
-
-	if (!pr)
-		return -EINVAL;
-	if (r->flags & IORESOURCE_IO) {
-		if (size > 0x100)
-			return -EFBIG;
-		if (allocate_resource(pr, r, size, 0x1000, ~0, 1024))
-			return -EBUSY;
-	} else {
-		if (allocate_resource(pr, r, size, 0x10000000, ~0, size))
-			return -EBUSY;
-	}
-	if (i < 6)
-		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start);
-	return 0;
-}
-
-/*
  * Several BIOS'es forget to assign addresses to I/O ranges. Try to fix it.
  */
 
@@ -824,7 +794,7 @@
 
 		r->start = 0;
 		r->end = size - 1;
-		if (pcibios_assign_resource(dev, idx)) {
+		if (pci_assign_resource(dev, idx)) {
 			printk(KERN_ERR "PCI: Unable to find free %d bytes of I/O space for device %s.\n", size, dev->name);
 			return;
 		}
@@ -852,7 +822,7 @@
 
 	r->start = 0;
 	r->end = rom_size - 1;
-	if (pcibios_assign_resource(dev, PCI_ROM_RESOURCE))
+	if (pci_assign_resource(dev, PCI_ROM_RESOURCE))
 		printk(KERN_ERR "PCI: Unable to find free space for expansion ROM of device %s (0x%lx bytes)\n",
 		       dev->name, rom_size);
 	else {
diff -u --recursive --new-file v2.3.17/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.3.17/linux/arch/i386/kernel/traps.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/i386/kernel/traps.c	Wed Sep  8 12:40:59 1999
@@ -20,6 +20,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #ifdef CONFIG_MCA
 #include <linux/mca.h>
@@ -29,7 +30,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/debugreg.h>
 #include <asm/desc.h>
@@ -357,11 +357,17 @@
 	unsigned int condition;
 	struct task_struct *tsk = current;
 
+	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
+
+	/* Mask out spurious debug traps due to lazy DR7 setting */
+	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+		if (!tsk->thread.debugreg[7])
+			goto clear_dr7;
+	}
+
 	if (regs->eflags & VM_MASK)
 		goto debug_vm86;
 
-	__asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
-
 	/* Mask out spurious TF errors due to lazy TF clearing */
 	if (condition & DR_STEP) {
 		/*
@@ -375,12 +381,6 @@
 		 */
 		if ((tsk->flags & (PF_DTRACE|PF_PTRACED)) == PF_DTRACE)
 			goto clear_TF;
-	}
-
-	/* Mask out spurious debug traps due to lazy DR7 setting */
-	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-		if (!tsk->thread.debugreg[7])
-			goto clear_dr7;
 	}
 
 	/* If this is a kernel mode trap, we need to reset db7 to allow us to continue sanely */
diff -u --recursive --new-file v2.3.17/linux/arch/m68k/hp300/ints.c linux/arch/m68k/hp300/ints.c
--- v2.3.17/linux/arch/m68k/hp300/ints.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/hp300/ints.c	Wed Sep  8 11:59:00 1999
@@ -15,13 +15,13 @@
 #include <linux/sched.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/traps.h>
 #include <asm/ptrace.h>
-#include <asm/spinlock.h>
 #include "ints.h"
 
 /* Each ipl has a linked list of interrupt service routines.
diff -u --recursive --new-file v2.3.17/linux/arch/m68k/sun3/config.c linux/arch/m68k/sun3/config.c
--- v2.3.17/linux/arch/m68k/sun3/config.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/sun3/config.c	Wed Sep  8 11:20:42 1999
@@ -57,7 +57,7 @@
 volatile char* clock_va; 
 extern unsigned char* sun3_intreg;
 
-__initfunc(void sun3_init(void))
+void __init sun3_init(void)
 {
 	unsigned char enable_register;
 	int i;
@@ -106,7 +106,7 @@
 	prom_reboot ("vmlinux");
 }
 
-__initfunc(void config_sun3(unsigned long *start_mem_p, unsigned long *end_mem_p))
+void __init config_sun3(unsigned long *start_mem_p, unsigned long *end_mem_p)
 {
 	printk("ARCH: SUN3\n");
 	idprom_init();
@@ -141,7 +141,7 @@
         *start_mem_p = sun_serial_setup(*start_mem_p);
 }
 
-__initfunc(void sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)))
+void __init sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))
 {
 	sun3_disable_interrupts();
         intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE);
diff -u --recursive --new-file v2.3.17/linux/arch/m68k/sun3/idprom.c linux/arch/m68k/sun3/idprom.c
--- v2.3.17/linux/arch/m68k/sun3/idprom.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/sun3/idprom.c	Wed Sep  8 11:20:42 1999
@@ -54,7 +54,7 @@
 //{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) }
 };
 
-__initfunc(static void display_system_type(unsigned char machtype))
+static void __init display_system_type(unsigned char machtype)
 {
 	register int i;
 
@@ -92,7 +92,7 @@
 
 
 /* Calculate the IDPROM checksum (xor of the data bytes). */
-__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom))
+static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
 {
 	unsigned char cksum, i, *ptr = (unsigned char *)idprom;
 
@@ -103,7 +103,7 @@
 }
 
 /* Create a local IDPROM copy, verify integrity, and display information. */
-__initfunc(void idprom_init(void))
+void __init idprom_init(void)
 {
 	prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
 
diff -u --recursive --new-file v2.3.17/linux/arch/m68k/sun3/prom/init.c linux/arch/m68k/sun3/prom/init.c
--- v2.3.17/linux/arch/m68k/sun3/prom/init.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/sun3/prom/init.c	Wed Sep  8 11:20:42 1999
@@ -30,7 +30,7 @@
 extern void prom_meminit(void);
 extern void prom_ranges_init(void);
 
-__initfunc(void prom_init(struct linux_romvec *rp))
+void __init prom_init(struct linux_romvec *rp)
 {
 #if CONFIG_AP1000
 	extern struct linux_romvec *ap_prom_init(void);
diff -u --recursive --new-file v2.3.17/linux/arch/m68k/sun3/sbus.c linux/arch/m68k/sun3/sbus.c
--- v2.3.17/linux/arch/m68k/sun3/sbus.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/sun3/sbus.c	Wed Sep  8 11:20:42 1999
@@ -12,7 +12,7 @@
 #include <linux/types.h>
 #include <linux/init.h>
 
-__initfunc(void sbus_init(void))
+void __init sbus_init(void)
 {
 
 }
diff -u --recursive --new-file v2.3.17/linux/arch/mips/jazz/io.c linux/arch/mips/jazz/io.c
--- v2.3.17/linux/arch/mips/jazz/io.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/jazz/io.c	Wed Sep  8 11:59:00 1999
@@ -8,10 +8,10 @@
  * Copyright (C) 1997 by Ralf Baechle.
  */
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <asm/mipsconfig.h>
 #include <asm/addrspace.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/jazz.h>
 
 /*
diff -u --recursive --new-file v2.3.17/linux/arch/mips/sni/io.c linux/arch/mips/sni/io.c
--- v2.3.17/linux/arch/mips/sni/io.c	Fri Jun 25 17:40:13 1999
+++ linux/arch/mips/sni/io.c	Wed Sep  8 11:59:00 1999
@@ -7,10 +7,10 @@
  * Low level I/O functions for SNI.
  */
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <asm/mipsconfig.h>
 #include <asm/addrspace.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/sni.h>
 
 /*
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.3.17/linux/arch/ppc/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/Makefile	Wed Sep  8 10:59:07 1999
@@ -106,6 +106,10 @@
 	@$(MAKECHRPBOOT) $@
 endif
 
+gemini_config:
+	rm -f .config arch/ppc/defconfig
+	ln -s gemini_defconfig arch/ppc/defconfig
+
 pmac_config:
 	rm -f .config arch/ppc/defconfig
 	ln -s pmac_defconfig arch/ppc/defconfig
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.3.17/linux/arch/ppc/boot/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/boot/Makefile	Wed Sep  8 10:59:07 1999
@@ -75,7 +75,10 @@
 	./mkprep -pbp zvmlinux zImage
 
 sImage: ../../../vmlinux
+ifdef CONFIG_GEMINI
 	$(OBJCOPY) -I elf32-powerpc -O binary ../../../vmlinux sImage
+else
+endif
 
 zImage.initrd: zvmlinux.initrd mkprep
 	./mkprep -pbp zvmlinux.initrd zImage.initrd
@@ -108,7 +111,9 @@
 
 znetboot : zImage
 	cp zImage $(TFTPIMAGE)
+ifdef CONFIG_GEMINI
 	cp sImage /tftpboot/
+endif
 
 znetboot.initrd : zImage.initrd
 	cp zImage.initrd $(TFTPIMAGE)
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S
--- v2.3.17/linux/arch/ppc/boot/head.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/boot/head.S	Wed Sep  8 10:59:07 1999
@@ -6,7 +6,7 @@
 	.text
 
 /*
- * $Id: head.S,v 1.32 1999/08/12 19:51:12 cort Exp $
+ * $Id: head.S,v 1.33 1999/09/08 01:06:58 cort Exp $
  *	
  * Boot loader philosophy:
  *      ROM loads us to some arbitrary location
@@ -125,10 +125,11 @@
 	 * get start address of kernel code which is stored as a coff
 	 * entry.  see boot/head.S -- Cort 
 	 */
-	li	r9,0x0
+	li	r9,0x4
 	mtlr	r9
 	lis	r10,0xdeadc0de@h
 	ori	r10,r10,0xdeadc0de@l
+	li	r9,0
 	stw	r10,0(r9)
 /*
  * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.17/linux/arch/ppc/config.in	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/config.in	Wed Sep  8 10:59:07 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.102 1999/08/30 10:06:53 davem Exp $
+# $Id: config.in,v 1.103 1999/09/01 19:04:44 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -17,6 +17,7 @@
 	 PReP/MTX	CONFIG_PREP \
 	 CHRP		CONFIG_CHRP \
 	 PowerMac/PReP/CHRP	CONFIG_ALL_PPC \
+	 Gemini		CONFIG_GEMINI \
   	 APUS           CONFIG_APUS \
 	 MBX		CONFIG_MBX" PowerMac
 
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/gemini_defconfig linux/arch/ppc/gemini_defconfig
--- v2.3.17/linux/arch/ppc/gemini_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/gemini_defconfig	Wed Sep  8 10:59:07 1999
@@ -0,0 +1,352 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_6xx=y
+# CONFIG_PPC64 is not set
+# CONFIG_8xx is not set
+# CONFIG_PMAC is not set
+# CONFIG_PREP is not set
+# CONFIG_CHRP is not set
+# CONFIG_ALL_PPC is not set
+CONFIG_GEMINI=y
+# CONFIG_APUS is not set
+# CONFIG_MBX is not set
+# CONFIG_SMP is not set
+CONFIG_MACH_SPECIFIC=y
+CONFIG_6xx=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+CONFIG_PCI=y
+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 is not set
+# CONFIG_PARPORT is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_FB is not set
+# CONFIG_PMAC_PBOOK is not set
+CONFIG_MAC_KEYBOARD=y
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_MAC_SERIAL is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_TOTALMP is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_MOTOROLA_HOTSWAP is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+# CONFIG_BLK_DEV_HD_ONLY is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+CONFIG_SYN_COOKIES=y
+CONFIG_SKB_LARGE=y
+# 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
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_SYM53C8XX=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
+# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_ETHERTAP is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+
+#
+# Token ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_SEALEVEL_4021 is not set
+# CONFIG_DLCI is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_PC_KEYB=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# Mice
+#
+CONFIG_BUSMOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_LOGIBUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_ADBMOUSE=y
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
+# CONFIG_RTC is not set
+
+#
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# USB drivers - not for the faint of heart
+#
+# CONFIG_USB is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# 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_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=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVPTS_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
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.3.17/linux/arch/ppc/kernel/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/Makefile	Wed Sep  8 10:59:07 1999
@@ -69,7 +69,7 @@
 	$(HOSTCC) $(HOSTCFLAGS) -o find_name find_name.c
 
 checks: checks.c
-	$(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -o checks checks.c
+	$(HOSTCC) -I$(HPATH) $(HOSTCFLAGS) -D__KERNEL__ -fno-builtin -o checks checks.c
 	./checks
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- v2.3.17/linux/arch/ppc/kernel/entry.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/entry.S	Wed Sep  8 10:59:07 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/entry.S
  *
- *  $Id: entry.S,v 1.2 1999/08/23 02:53:16 paulus Exp $
+ *  $Id: entry.S,v 1.3 1999/09/05 11:56:26 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -291,14 +291,12 @@
 	.globl	ret_from_except
 ret_from_except:
 0:	mfmsr	r30		/* Disable interrupts */
-	li	r3,0
-	ori	r3,r3,MSR_EE
-	andc	r30,r30,r3
+	rlwinm	r30,r30,0,17,15	/* clear MSR_EE */
 	SYNC			/* Some chip revs need this... */
 	mtmsr	r30
 	SYNC
 	lwz	r5,_MSR(r1)
-	and.	r5,r5,r4
+	andi.	r5,r5,MSR_EE
 	beq	2f
 3:	lis	r4,ppc_n_lost_interrupts@ha
 	lwz	r4,ppc_n_lost_interrupts@l(r4)
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/gemini_pci.c linux/arch/ppc/kernel/gemini_pci.c
--- v2.3.17/linux/arch/ppc/kernel/gemini_pci.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/gemini_pci.c	Wed Sep  8 10:59:07 1999
@@ -152,7 +152,7 @@
 
 
 
-static __init void layout_dev( struct pci_dev *dev )
+__init void layout_dev( struct pci_dev *dev )
 {
 	int i;
 	struct pci_bus *bus;
@@ -225,7 +225,7 @@
 					  (cmd|PCI_COMMAND_MASTER));
 }
 
-static __init void layout_bus( struct pci_bus *bus )
+__init void layout_bus( struct pci_bus *bus )
 {
 	struct pci_dev *dev;
 
@@ -246,12 +246,9 @@
 {
 	struct pci_bus *bus;
 	unsigned long orig_mem_base, orig_io_base;
-
+	
 	orig_mem_base = pci_mem_base;
 	orig_io_base = pci_io_base;
-
-	for( bus = &pci_root; bus; bus = bus->children )
-		layout_bus( bus );
 
 	pci_mem_base = orig_mem_base;
 	pci_io_base = orig_io_base;
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.3.17/linux/arch/ppc/kernel/gemini_setup.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/ppc/kernel/gemini_setup.c	Wed Sep  8 10:59:07 1999
@@ -480,6 +480,8 @@
 			unsigned long r6, unsigned long r7)
 {
 	void chrp_do_IRQ(struct pt_regs *, int, int);
+	void layout_bus( struct pci_bus * );
+ 
 	gemini_setup_pci_ptrs();
 
 	ISA_DMA_THRESHOLD = 0;
@@ -521,4 +523,5 @@
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.ppc_kbd_sysrq_xlate = NULL;
 #endif
+	ppc_md.pcibios_fixup_bus = layout_bus;
 }
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/hashtable.S linux/arch/ppc/kernel/hashtable.S
--- v2.3.17/linux/arch/ppc/kernel/hashtable.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/hashtable.S	Wed Sep  8 10:59:07 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/hashtable.S
  *
- *  $Id: hashtable.S,v 1.2 1999/08/23 02:53:17 paulus Exp $
+ *  $Id: hashtable.S,v 1.3 1999/09/05 11:56:27 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -318,11 +318,14 @@
 	eieio
 	blr
 
+	.data
 	.globl	hash_table_lock
 hash_table_lock:
 	.long	0
-#endif
+	.text
+#endif /* __SMP__ */
 
+/* next_slot is assumed to be within the first 32kB of physical RAM */
 next_slot:
 	.long	0
 
@@ -467,9 +470,8 @@
 #ifdef __SMP__
 	tlbsync
 	sync
-	lis	r3,hash_table_lock@h
 	li	r0,0
-	stw	r0,hash_table_lock@l(r3)
+	stw	r0,0(r9)		/* clear hash_table_lock */
 	mtmsr	r10
 	SYNC
 #endif
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.17/linux/arch/ppc/kernel/head.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/head.S	Wed Sep  8 10:59:07 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.142 1999/08/23 02:53:18 paulus Exp $
+ *  $Id: head.S,v 1.143 1999/09/05 11:56:28 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -143,6 +143,7 @@
 	mr	r27,r7
 	li	r24,0			/* cpu # */
 	bl	prom_init
+
 #ifdef CONFIG_APUS
 /* On APUS the __va/__pa constants need to be set to the correct 
  * values before continuing. 
@@ -150,15 +151,14 @@
 	mr	r4,r30
 	bl	fix_mem_constants
 #endif
-	.globl	__secondary_start
-__secondary_start:
+
 /*
  * Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.  From this point on we can't safely
  * call OF any more.
  */
 	lis	r11,KERNELBASE@h
-#ifndef CONFIG_PPC64
+#ifndef CONFIG_PPC64xxx
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpi	0,r9,1
@@ -189,8 +189,15 @@
 	 * allow secondary cpus to get at all of ram in early bootup
 	 * since their init_task may be up there -- Cort
 	 */
+#if 0
 	oris	r18,r8,0x10000000@h
 	oris	r21,r11,(KERNELBASE+0x10000000)@h
+#else
+	lis	r18,0x9000
+	ori	r18,r18,0x12
+	lis	r21,0x9000
+	ori	r21,r21,0x7fe
+#endif
 	mtspr	DBAT1L,r18		/* N.B. 6xx (not 601) have valid */
 	mtspr	DBAT1U,r21		/* bit in upper BAT register */
 	mtspr	IBAT1L,r18
@@ -330,7 +337,7 @@
 	STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)
 #else
 	STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif	
+#endif
 
 /* Machine check */
 	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -982,11 +989,6 @@
 #endif
 
 #ifdef CONFIG_SMP
-	.globl	__secondary_start_psurge
-__secondary_start_psurge:
-	li	r24,1			/* cpu # */
-	b	__secondary_start
-
 	.globl	__secondary_hold
 __secondary_hold:
 	/* tell the master we're here */
@@ -1008,15 +1010,59 @@
 	mtlr	r5
 	mr	r24,r3			/* cpu # */
 	blr
+
+	.globl	__secondary_start_psurge
+__secondary_start_psurge:
+	li	r24,1			/* cpu # */
+	/* we come in here with IR=0 and DR=1, and DBAT 0
+	   set to map the 0xf0000000 - 0xffffffff region */
+	mfmsr	r0
+	rlwinm	r0,r0,0,28,26		/* clear DR (0x10) */
+	sync
+	mtmsr	r0
+	isync
+
+	.globl	__secondary_start
+__secondary_start:
+	bl	enable_caches
+
+	/* get current */
+	lis	r2,current_set@h
+	ori	r2,r2,current_set@l
+	tophys(r2,r2)
+	slwi	r24,r24,2		/* get current_set[cpu#] */
+	lwzx	r2,r2,r24
+
+	/* stack */
+	addi	r1,r2,TASK_UNION_SIZE-STACK_FRAME_OVERHEAD
+	li	r0,0
+	tophys(r3,r1)
+	stw	r0,0(r3)
+
+	/* load up the MMU */
+	bl	load_up_mmu
+
+	/* ptr to phys current thread */
+	tophys(r4,r2)
+	addi	r4,r4,THREAD	/* phys address of our thread_struct */
+	mtspr	SPRG3,r4
+	li	r3,0
+	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
+
+	/* enable MMU and jump to start_secondary */
+	li	r4,MSR_KERNEL
+	lis	r3,start_secondary@h
+	ori	r3,r3,start_secondary@l
+	mtspr	SRR0,r3
+	mtspr	SRR1,r4
+	rfi
+
 #endif /* CONFIG_SMP */
-	
+
 /*
- * This is where the main kernel code starts.
+ * Enable caches and 604-specific features if necessary.
  */
-start_here:
-	/*
-	 * Enable caches and 604-specific features if necessary.
-	 */
+enable_caches:
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31
 	cmpi	0,r9,1
@@ -1044,25 +1090,57 @@
 	bne	2,5f
 	ori	r11,r11,HID0_BTCD
 5:	mtspr	HID0,r11		/* superscalar exec & br history tbl */
-4:
-#ifdef __SMP__
-	/* if we're the second cpu stack and r2 are different
-	* and we want to not clear the bss -- Cort */
-	lis	r5,first_cpu_booted@h
-	ori	r5,r5,first_cpu_booted@l
-	lwz	r5,0(r5)
-	cmpi	0,r5,0
-	beq	99f
+4:	blr
+
+/*
+ * Load stuff into the MMU.  Intended to be called with
+ * IR=0 and DR=0.
+ */
+load_up_mmu:
+	/* Load the SDR1 register (hash table base & size) */
+	lis	r6,_SDR1@ha
+	tophys(r6,r6)
+#ifdef CONFIG_PPC64	
+	ld	r6,_SDR1@l(r6)
+	mtspr	SDR1,r6
+	/* clear the v bit in the ASR so we can
+	 * behave as if we have segment registers 
+	 * -- Cort
+	 */
+	clrldi	r6,r6,63
+	mtasr	r6
+#else
+	lwz	r6,_SDR1@l(r6)
+	mtspr	SDR1,r6
+#endif /* CONFIG_PPC64 */
+	li	r0,16		/* load up segment register values */
+	mtctr	r0		/* for context 0 */
+	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
+	li	r4,0
+3:	mtsrin	r3,r4
+	addi	r3,r3,1		/* increment VSID */
+	addis	r4,r4,0x1000	/* address of next segment */
+	bdnz	3b
+/* Load the BAT registers with the values set up by MMU_init.
+   MMU_init takes care of whether we're on a 601 or not. */
+	mfpvr	r3
+	srwi	r3,r3,16
+	cmpwi	r3,1
+	lis	r3,BATS@ha
+	addi	r3,r3,BATS@l
+	tophys(r3,r3)
+	LOAD_BAT(0,r3,r4,r5)
+	LOAD_BAT(1,r3,r4,r5)
+	LOAD_BAT(2,r3,r4,r5)
+	LOAD_BAT(3,r3,r4,r5)
+	blr
+
+/*
+ * This is where the main kernel code starts.
+ */
+start_here:
+	bl	enable_caches
 
-	/* get current */
-	lis	r2,current_set@h
-	ori	r2,r2,current_set@l
-	slwi	r24,r24,2			/* cpu # to current_set[cpu#] */
-	add	r2,r2,r24
-	lwz	r2,0(r2)
-	b	10f
-99:	
-#endif /* __SMP__ */
 	/* ptr to current */
 	lis	r2,init_task_union@h
 	ori	r2,r2,init_task_union@l
@@ -1081,9 +1159,6 @@
 3:	stwu	r0,4(r8)
 	bdnz	3b
 2:
-#ifdef __SMP__	
-10:
-#endif /* __SMP__ */
 	/* stack */
 	addi	r1,r2,TASK_UNION_SIZE
 	li	r0,0
@@ -1104,12 +1179,6 @@
  * for SDR1 (hash table pointer) and the segment registers
  * and change to using our exception vectors.
  */
-	lis	r6,_SDR1@ha
-#ifdef CONFIG_PPC64	
-	ld	r6,_SDR1@l(r6)
-#else
-	lwz	r6,_SDR1@l(r6)
-#endif		
 	lis	r4,2f@h
 	ori	r4,r4,2f@l
 	tophys(r4,r4)
@@ -1126,42 +1195,7 @@
 	tlbsync			/* ... on all CPUs */
 	sync
 #endif
-	mtspr	SDR1,r6
-#ifdef CONFIG_PPC64
-	/* clear the v bit in the ASR so we can
-	 * behave as if we have segment registers 
-	 * -- Cort
-	 */
-	clrldi	r6,r6,63
-	mtasr	r6
-#endif /* CONFIG_PPC64 */
-	li	r0,16		/* load up segment register values */
-	mtctr	r0		/* for context 0 */
-	lis	r3,0x2000	/* Ku = 1, VSID = 0 */
-	li	r4,0
-3:	mtsrin	r3,r4
-	addi	r3,r3,1		/* increment VSID */
-	addis	r4,r4,0x1000	/* address of next segment */
-	bdnz	3b
-/* Load the BAT registers with the values set up by MMU_init.
-   MMU_init takes care of whether we're on a 601 or not. */
-	mfpvr	r3
-	srwi	r3,r3,16
-	cmpwi	r3,1
-	lis	r3,BATS@ha
-	addi	r3,r3,BATS@l
-	tophys(r3,r3)
-#ifdef CONFIG_PPC64
-	LOAD_BAT(0,r3,r4,r5)
-	LOAD_BAT(1,r3,r4,r5)
-	LOAD_BAT(2,r3,r4,r5)
-	LOAD_BAT(3,r3,r4,r5)
-#else /* CONFIG_PPC64 */
-	LOAD_BAT(0,r3,r4,r5)
-	LOAD_BAT(1,r3,r4,r5)
-	LOAD_BAT(2,r3,r4,r5)
-	LOAD_BAT(3,r3,r4,r5)
-#endif /* CONFIG_PPC64 */
+	bl	load_up_mmu
 
 /* Set up for using our exception vectors */
 	/* ptr to phys current thread */
@@ -1174,20 +1208,6 @@
 	li	r4,MSR_KERNEL
 	lis	r3,start_kernel@h
 	ori	r3,r3,start_kernel@l
-#ifdef __SMP__
-	/* the second time through here we go to
-	 * start_secondary(). -- Cort
-	 */
-	lis	r5,first_cpu_booted@h
-	ori	r5,r5,first_cpu_booted@l
-	tophys(r5,r5)
-	lwz	r5,0(r5)
-	cmpi	0,r5,0
-	beq	10f
-	lis	r3,start_secondary@h
-	ori	r3,r3,start_secondary@l
-10:	
-#endif /* __SMP__ */
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
 	rfi			/* enable MMU and jump to start_kernel */
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.3.17/linux/arch/ppc/kernel/idle.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/idle.c	Wed Sep  8 10:59:07 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.65 1999/08/03 19:16:19 cort Exp $
+ * $Id: idle.c,v 1.66 1999/09/05 11:56:30 paulus Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -45,7 +45,7 @@
 unsigned long zeropage_calls; /* # zero'd pages request that've been made */
 unsigned long zerototal;      /* # pages zero'd over time */
 
-int idled(void *unused)
+int idled(void)
 {
 	/* endless loop with no priority at all */
 	current->priority = 0;
@@ -73,9 +73,9 @@
  * SMP entry into the idle task - calls the same thing as the
  * non-smp versions. -- Cort
  */
-int cpu_idle(void *unused)
+int cpu_idle()
 {
-	idled(unused);
+	idled();
 	return 0; 
 }
 
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.17/linux/arch/ppc/kernel/irq.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/irq.c	Wed Sep  8 10:59:07 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: irq.c,v 1.108 1999/07/23 01:55:44 davem Exp $
+ * $Id: irq.c,v 1.109 1999/09/05 11:56:31 paulus Exp $
  *
  *  arch/ppc/kernel/irq.c
  *
@@ -31,6 +31,7 @@
 
 #include <linux/ptrace.h>
 #include <linux/errno.h>
+#include <linux/threads.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.17/linux/arch/ppc/kernel/misc.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/misc.S	Wed Sep  8 10:59:07 1999
@@ -45,13 +45,7 @@
 	mtlr	r0
 	blr
 
-/*
- * Disable interrupts
- *	rc = _disable_interrupts()
- */
-_GLOBAL(_disable_interrupts)
 _GLOBAL(__cli)
-_GLOBAL(_hard_cli)
 	mfmsr	r0		/* Get current interrupt state */
 	rlwinm	r3,r0,16+1,32-1,31	/* Extract old value of 'EE' */
 	li	r4,0		/* Need [unsigned] value of MSR_EE */
@@ -61,16 +55,7 @@
 	mtmsr	r0		/* Update machine state */
 	blr			/* Done */
 
-/*
- * Enable interrupts
- *	_enable_interrupts(int state)
- * turns on interrupts if state = 1.
- */
-_GLOBAL(_enable_interrupts)
-	cmpi	0,r3,0		/* turning them on? */
-	beqlr			/* nothing to do if state == 0 */
 _GLOBAL(__sti)
-_GLOBAL(_hard_sti)
 	lis	r4,ppc_n_lost_interrupts@ha
 	lwz	r4,ppc_n_lost_interrupts@l(r4)
 	mfmsr	r3		/* Get current state */
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.3.17/linux/arch/ppc/kernel/pci.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/pci.c	Wed Sep  8 10:59:07 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: pci.c,v 1.56 1999/08/31 15:42:37 cort Exp $
+ * $Id: pci.c,v 1.60 1999/09/08 03:04:07 cort Exp $
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
@@ -22,6 +22,8 @@
 
 #include "pci.h"
 
+static void __init pcibios_claim_resources(struct pci_bus *);
+
 unsigned long isa_io_base     = 0;
 unsigned long isa_mem_base    = 0;
 unsigned long pci_dram_offset = 0;
@@ -68,17 +70,46 @@
 void __init pcibios_init(void)
 {
 	printk("PCI: Probing PCI hardware\n");
+	ioport_resource.end = ~0L;
 	pci_scan_bus(0, &generic_pci_ops, NULL);
-	
-}
-
-void __init pcibios_fixup(void)
-{
-	ppc_md.pcibios_fixup();
+	pcibios_claim_resources(pci_root);
+	if ( ppc_md.pcibios_fixup )
+		ppc_md.pcibios_fixup();
+}
+
+static void __init pcibios_claim_resources(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+	int idx;
+
+	while (bus)
+	{
+		for (dev=bus->devices; dev; dev=dev->sibling)
+		{
+			for (idx = 0; idx < PCI_NUM_RESOURCES; idx++)
+			{
+				struct resource *r = &dev->resource[idx];
+				struct resource *pr;
+				if (!r->start)
+					continue;
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0)
+				{
+					printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name);
+					/* We probably should disable the region, shouldn't we? */
+				}
+			}
+		}
+		if (bus->children)
+			pcibios_claim_resources(bus->children);
+		bus = bus->next;
+	}
 }
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
 {
+	if ( ppc_md.pcibios_fixup_bus )
+		ppc_md.pcibios_fixup_bus(bus);
 }
 
 char __init *pcibios_setup(char *str)
@@ -110,3 +141,8 @@
 	}
 }
 #endif
+
+int pcibios_assign_resource(struct pci_dev *pdev, int resource)
+{
+	return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.17/linux/arch/ppc/kernel/ppc_ksyms.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Wed Sep  8 11:59:00 1999
@@ -8,6 +8,7 @@
 #include <linux/interrupt.h>
 #include <linux/vt_kern.h>
 #include <linux/nvram.h>
+#include <linux/spinlock.h>
 
 #include <asm/page.h>
 #include <asm/semaphore.h>
@@ -28,7 +29,6 @@
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
 #include <asm/feature.h>
-#include <asm/spinlock.h>
 #include <asm/dma.h>
 #include <asm/machdep.h>
 
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.17/linux/arch/ppc/kernel/prom.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/prom.c	Wed Sep  8 11:59:00 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.70 1999/08/25 21:26:08 cort Exp $
+ * $Id: prom.c,v 1.73 1999/09/05 11:56:32 paulus Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -16,9 +16,10 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/version.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
 
 #include <asm/init.h>
-#include <asm/spinlock.h>
 #include <asm/prom.h>
 #include <asm/page.h>
 #include <asm/processor.h>
@@ -27,6 +28,7 @@
 #include <asm/smp.h>
 #include <asm/bootx.h>
 #include <asm/system.h>
+#include <asm/gemini.h>
 
 /*
  * Properties whose value is longer than this get excluded from our
@@ -281,6 +283,11 @@
 	int l;
 	char *p, *d;
 
+#ifdef CONFIG_GEMINI
+	gemini_prom_init();
+	return;
+#endif /* CONFIG_GEMINI */
+	
 	/* check if we're apus, return if we are */
 	if ( r3 == 0x61707573 )
 		return;
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.17/linux/arch/ppc/kernel/setup.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/setup.c	Wed Sep  8 10:59:07 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.146 1999/08/31 06:54:08 davem Exp $
+ * $Id: setup.c,v 1.148 1999/09/05 11:56:34 paulus Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -279,9 +279,11 @@
 				for ( s = 0; (s < i) && cpu_node->next ;
 				      s++, cpu_node = cpu_node->next )
 					/* nothing */ ;
+#if 0 /* SMP Pmacs don't have all cpu nodes -- Cort */
 				if ( s != i )
 					printk("get_cpuinfo(): ran out of "
 					       "cpu nodes.\n");
+#endif
 			}
 			fp = (int *) get_property(cpu_node, "clock-frequency", NULL);
 			if ( !fp ) break;
@@ -343,7 +345,6 @@
 identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 		 unsigned long r6, unsigned long r7)
 {
-	
 #ifdef __SMP__
 	if ( first_cpu_booted ) return 0;
 #endif /* __SMP__ */
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.17/linux/arch/ppc/kernel/smp.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/kernel/smp.c	Wed Sep  8 11:59:00 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.61 1999/08/24 22:06:26 cort Exp $
+ * $Id: smp.c,v 1.62 1999/09/05 11:56:34 paulus Exp $
  *
  * Smp support for ppc.
  *
@@ -21,13 +21,13 @@
 #include <linux/unistd.h>
 #include <linux/init.h>
 #include <linux/openpic.h>
+#include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/init.h>
@@ -253,16 +253,18 @@
 	/* let other processors know to not do certain initialization */
 	first_cpu_booted = 1;
 	smp_num_cpus = 1;
-	
+        smp_store_cpu_info(0);
+
 	/*
 	 * assume for now that the first cpu booted is
 	 * cpu 0, the master -- Cort
 	 */
 	cpu_callin_map[0] = 1;
-        smp_store_cpu_info(0);
         active_kernel_processor = 0;
 	current->processor = 0;
 
+	init_idle();
+
 	for (i = 0; i < NR_CPUS; i++) {
 		prof_counter[i] = 1;
 		prof_multiplier[i] = 1;
@@ -304,12 +306,21 @@
 	for ( i = 1 ; i < cpu_nr; i++ )
 	{
 		int c;
+		struct pt_regs regs;
+		struct task_struct *idle;
 		
 		/* create a process for the processor */
-		kernel_thread(start_secondary, NULL, CLONE_PID);
-		p = init_tasks[i];
-		if ( !p )
-			panic("No idle task for secondary processor\n");
+		/* we don't care about the values in regs since we'll
+		   never reschedule the forked task. */
+		if (do_fork(CLONE_VM|CLONE_PID, 0, &regs) < 0)
+			panic("failed fork for CPU %d", i);
+		p = init_task.prev_task;
+		if (!p)
+			panic("No idle task for CPU %d", i);
+		del_from_runqueue(p);
+		unhash_process(p);
+		init_tasks[i] = p;
+
 		p->processor = i;
 		p->has_cpu = 1;
 		current_set[i] = p;
@@ -329,6 +340,7 @@
 			eieio();
 			/* interrupt secondary to begin executing code */
 			out_be32(PSURGE_INTR, ~0);
+			udelay(1);
 			out_be32(PSURGE_INTR, 0);
 			break;
 		case _MACH_chrp:
@@ -385,6 +397,7 @@
 	/*
 	 *	Lets the callin's below out of their loop.
 	 */
+	wmb();
 	smp_commenced = 1;
 }
 
@@ -394,8 +407,10 @@
 }
 
 /* Activate a secondary processor. */
-asmlinkage int __init start_secondary(void *unused)
+int __init start_secondary(void *unused)
 {
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
 	smp_callin();
 	return cpu_idle(NULL);
 }
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.3.17/linux/arch/ppc/kernel/syscalls.c	Mon Jun 28 13:40:39 1999
+++ linux/arch/ppc/kernel/syscalls.c	Wed Sep  8 10:59:07 1999
@@ -37,6 +37,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
+#include <asm/semaphore.h>
 
 void
 check_bugs(void)
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c
--- v2.3.17/linux/arch/ppc/lib/locks.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/lib/locks.c	Wed Sep  8 11:59:00 1999
@@ -10,9 +10,9 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 #include <asm/processor.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/io.h>
 
 #define DEBUG_LOCKS 1
diff -u --recursive --new-file v2.3.17/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.17/linux/arch/ppc/mm/init.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/ppc/mm/init.c	Wed Sep  8 10:59:07 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.180 1999/08/31 06:54:13 davem Exp $
+ *  $Id: init.c,v 1.183 1999/09/05 19:29:44 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -90,8 +90,7 @@
 unsigned long *mbx_find_end_of_memory(void);
 #endif /* CONFIG_MBX */
 static void mapin_ram(void);
-void map_page(struct task_struct *, unsigned long va,
-		     unsigned long pa, int flags);
+void map_page(unsigned long va, unsigned long pa, int flags);
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
 
@@ -436,7 +435,7 @@
 	 */
 	
 	for (i = 0; i < size; i += PAGE_SIZE)
-		map_page(&init_task, v+i, p+i, flags);
+		map_page(v+i, p+i, flags);
 out:	
 	return (void *) (v + (addr & ~PAGE_MASK));
 }
@@ -472,13 +471,19 @@
 }
 
 void
-map_page(struct task_struct *tsk, unsigned long va,
-	 unsigned long pa, int flags)
+map_page(unsigned long va, unsigned long pa, int flags)
 {
-	pte_t * pte;
-
-	pte = pte_alloc(pmd_offset(pgd_offset_k(va), va), va);
-	set_pte(pte, mk_pte_phys(pa, __pgprot(flags)));
+	pmd_t *pd, oldpd;
+	pte_t *pg;
+	
+	/* Use upper 10 bits of VA to index the first level map */
+	pd = pmd_offset(pgd_offset_k(va), va);
+	oldpd = *pd;
+	/* Use middle 10 bits of VA to index the second-level map */
+	pg = pte_alloc(pd, va);
+	if (pmd_none(oldpd) && mem_init_done)
+		set_pgdir(va, *(pgd_t *)pd);
+	set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
 	flush_hash_page(0, va);
 }
 
@@ -856,7 +861,6 @@
 			       RAM_PAGE);
 		}
 	}
-
 	v = KERNELBASE;
 	for (i = 0; i < phys_mem.n_regions; ++i) {
 		p = phys_mem.regions[i].address;
@@ -868,11 +872,11 @@
 				/* On the powerpc, no user access
 				   forces R/W kernel access */
 				f |= _PAGE_USER;
-			map_page(&init_task, v, p, f);
+			map_page(v, p, f);
 			v += PAGE_SIZE;
 			p += PAGE_SIZE;
 		}
-	}	    
+	}
 
 #else	/* CONFIG_8xx */
 
@@ -895,7 +899,7 @@
                          */
 			if ((char *) v < _stext || (char *) v >= etext)
 				f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
-			map_page(&init_task, v, p, f);
+			map_page(v, p, f);
 			v += PAGE_SIZE;
 			p += PAGE_SIZE;
 		}
@@ -957,6 +961,11 @@
 		FREESEC(__prep_begin,__prep_end,num_prep_pages);
 		break;
 	case _MACH_apus:
+		FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
+		FREESEC(__prep_begin,__prep_end,num_prep_pages);
+		break;
+	case _MACH_gemini:
+		FREESEC(__apus_begin,__apus_end,num_apus_pages);
 		FREESEC(__pmac_begin,__pmac_end,num_pmac_pages);
 		FREESEC(__prep_begin,__prep_end,num_prep_pages);
 		break;
diff -u --recursive --new-file v2.3.17/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c
--- v2.3.17/linux/arch/sh/kernel/traps.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sh/kernel/traps.c	Wed Sep  8 11:59:00 1999
@@ -19,11 +19,11 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <asm/atomic.h>
 
 static inline void console_verbose(void)
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.3.17/linux/arch/sparc/kernel/irq.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/irq.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.96 1999/08/31 06:54:21 davem Exp $
+/*  $Id: irq.c,v 1.97 1999/09/10 10:40:21 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -26,6 +26,7 @@
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/threads.h>
+#include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -40,7 +41,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/pcic.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.3.17/linux/arch/sparc/kernel/setup.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/setup.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.110 1999/08/31 06:54:23 davem Exp $
+/*  $Id: setup.c,v 1.111 1999/09/10 10:40:24 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/console.h>
+#include <linux/spinlock.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -40,7 +41,6 @@
 #include <asm/kdebug.h>
 #include <asm/mbus.h>
 #include <asm/idprom.h>
-#include <asm/spinlock.h>
 #include <asm/softirq.h>
 #include <asm/hardirq.h>
 #include <asm/machines.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.3.17/linux/arch/sparc/kernel/smp.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sparc/kernel/smp.c	Wed Sep  8 11:59:00 1999
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -24,7 +25,6 @@
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
 #include <asm/atops.h>
-#include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.3.17/linux/arch/sparc/kernel/sparc_ksyms.c	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.78 1999/07/23 01:56:15 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.79 1999/09/10 10:40:28 davem Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/in6.h>
+#include <linux/spinlock.h>
 
 #include <asm/oplib.h>
 #include <asm/delay.h>
@@ -29,7 +30,6 @@
 #include <asm/smp.h>
 #include <asm/mostek.h>
 #include <asm/ptrace.h>
-#include <asm/spinlock.h>
 #include <asm/softirq.h>
 #include <asm/hardirq.h>
 #include <asm/user.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c
--- v2.3.17/linux/arch/sparc/kernel/sun4d_irq.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/sun4d_irq.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/*  $Id: sun4d_irq.c,v 1.19 1999/08/31 06:54:25 davem Exp $
+/*  $Id: sun4d_irq.c,v 1.20 1999/09/10 10:40:30 davem Exp $
  *  arch/sparc/kernel/sun4d_irq.c:
  *			SS1000/SC2000 interrupt handling.
  *
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -32,7 +33,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/spinlock.h>
 #include <asm/sbus.h>
 #include <asm/sbi.h>
 
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- v2.3.17/linux/arch/sparc/kernel/sun4d_smp.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sparc/kernel/sun4d_smp.c	Wed Sep  8 11:59:00 1999
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -27,7 +28,6 @@
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
 #include <asm/atops.h>
-#include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/sbus.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- v2.3.17/linux/arch/sparc/kernel/sun4m_smp.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sparc/kernel/sun4m_smp.c	Wed Sep  8 11:59:00 1999
@@ -13,6 +13,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -23,7 +24,6 @@
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
 #include <asm/atops.h>
-#include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/lib/debuglocks.c linux/arch/sparc/lib/debuglocks.c
--- v2.3.17/linux/arch/sparc/lib/debuglocks.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/lib/debuglocks.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: debuglocks.c,v 1.9 1999/08/14 03:51:39 anton Exp $
+/* $Id: debuglocks.c,v 1.10 1999/09/10 10:40:36 davem Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,9 +8,9 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/threads.h>	/* For NR_CPUS */
+#include <linux/spinlock.h>
 #include <asm/psr.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 /* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
 #ifdef SPIN_LOCK_DEBUG
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.3.17/linux/arch/sparc/mm/init.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/mm/init.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.68 1999/08/31 06:54:32 davem Exp $
+/*  $Id: init.c,v 1.69 1999/09/06 22:56:17 ecd Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -379,4 +379,6 @@
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
+	val->totalbig = 0;
+	val->freebig = 0;
 }
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/mm/io-unit.c linux/arch/sparc/mm/io-unit.c
--- v2.3.17/linux/arch/sparc/mm/io-unit.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/mm/io-unit.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.14 1999/08/31 06:54:33 davem Exp $
+/* $Id: io-unit.c,v 1.15 1999/09/10 10:40:38 davem Exp $
  * io-unit.c:  IO-UNIT specific routines for memory management.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
@@ -8,12 +8,12 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
+#include <linux/spinlock.h>
 #include <asm/pgtable.h>
 #include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/io-unit.h>
 #include <asm/mxcc.h>
-#include <asm/spinlock.h>
 #include <asm/bitops.h>
 
 /* #define IOUNIT_DEBUG */
diff -u --recursive --new-file v2.3.17/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.3.17/linux/arch/sparc/mm/srmmu.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/mm/srmmu.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.191 1999/08/31 06:54:38 davem Exp $
+/* $Id: srmmu.c,v 1.192 1999/09/10 10:40:40 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/blk.h>
+#include <linux/spinlock.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -32,7 +33,6 @@
 #include <asm/a.out.h>
 #include <asm/mmu_context.h>
 #include <asm/io-unit.h>
-#include <asm/spinlock.h>
 
 /* Now the cpu specific definitions. */
 #include <asm/viking.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.17/linux/arch/sparc64/config.in	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/config.in	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.77 1999/08/31 12:49:42 davem Exp $
+# $Id: config.in,v 1.78 1999/09/06 01:17:28 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -204,6 +204,9 @@
 		if [ "$CONFIG_PCI" = "y" ]; then
 			tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
 			tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
+			tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
+			tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
+			tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
 			tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
 		fi
 #		bool 'FDDI driver support' CONFIG_FDDI
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.17/linux/arch/sparc64/defconfig	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/defconfig	Wed Sep  8 11:14:32 1999
@@ -71,6 +71,7 @@
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
 CONFIG_SUN_AURORA=m
+# CONFIG_TADPOLE_TS102_UCTRL is not set
 CONFIG_APM_RTC_IS_GMT=y
 # CONFIG_RTC is not set
 
@@ -257,6 +258,9 @@
 CONFIG_MYRI_SBUS=m
 CONFIG_DE4X5=m
 CONFIG_VORTEX=m
+CONFIG_RTL8139=m
+CONFIG_NE2K_PCI=m
+CONFIG_EEXPRESS_PRO100=m
 CONFIG_ADAPTEC_STARFIRE=m
 
 #
@@ -286,6 +290,8 @@
 CONFIG_EFS_FS=m
 CONFIG_ISO9660_FS=m
 # CONFIG_JOLIET is not set
+CONFIG_UDF_FS=m
+# CONFIG_UDF_RW is not set
 CONFIG_MINIX_FS=m
 # CONFIG_NTFS_FS is not set
 CONFIG_HPFS_FS=m
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.3.17/linux/arch/sparc64/kernel/cpu.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/cpu.c	Wed Sep  8 11:14:32 1999
@@ -33,7 +33,7 @@
   { 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
-  { 0x17, 0x13, 0, "UltraSparc III integrated FPU"},
+  { 0x17, 0x14, 0, "UltraSparc III integrated FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -43,7 +43,7 @@
   { 0x22, 0x10, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x12, "TI UltraSparc IIi"},
-  { 0x17, 0x13, "TI UltraSparc III (Cheetah)"},  /* A guess... */
+  { 0x17, 0x14, "TI UltraSparc III (Cheetah)"},  /* A guess... */
 };
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- v2.3.17/linux/arch/sparc64/kernel/ebus.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/ebus.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.42 1999/08/31 09:12:31 davem Exp $
+/* $Id: ebus.c,v 1.44 1999/09/05 09:28:09 ecd Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -77,7 +77,7 @@
 }
 
 void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
-			    struct linux_ebus_child *dev)
+			    struct linux_ebus_child *dev, int non_standard_regs)
 {
 	int regs[PROMREG_MAX];
 	int irqs[PROMREG_MAX];
@@ -85,22 +85,34 @@
 
 	dev->prom_node = node;
 	prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
-	printk("(%s)", dev->prom_name);
+	printk(" (%s)", dev->prom_name);
 
 	len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
 	dev->num_addrs = len / sizeof(regs[0]);
 
-	for (i = 0; i < dev->num_addrs; i++) {
-		int rnum = regs[i];
-		if (rnum >= dev->parent->num_addrs) {
-			prom_printf("UGH: property for %s was %d, need < %d\n",
-				    dev->prom_name, len, dev->parent->num_addrs);
-			panic(__FUNCTION__);
+	if (non_standard_regs) {
+		/* This is to handle reg properties which are not
+		 * in the parent relative format.  One example are
+		 * children of the i2c device on CompactPCI systems.
+		 *
+		 * So, for such devices we just record the property
+		 * raw in the child resources.
+		 */
+		for (i = 0; i < dev->num_addrs; i++)
+			dev->resource[i].start = regs[i];
+	} else {
+		for (i = 0; i < dev->num_addrs; i++) {
+			int rnum = regs[i];
+			if (rnum >= dev->parent->num_addrs) {
+				prom_printf("UGH: property for %s was %d, need < %d\n",
+					    dev->prom_name, len, dev->parent->num_addrs);
+				panic(__FUNCTION__);
+			}
+			dev->resource[i].start = dev->parent->resource[i].start;
+			dev->resource[i].end = dev->parent->resource[i].end;
+			dev->resource[i].flags = IORESOURCE_MEM;
+			dev->resource[i].name = dev->prom_name;
 		}
-		dev->resource[i].start = dev->parent->resource[i].start;
-		dev->resource[i].end = dev->parent->resource[i].end;
-		dev->resource[i].flags = IORESOURCE_MEM;
-		dev->resource[i].name = dev->prom_name;
 	}
 
 	len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
@@ -133,6 +145,13 @@
 	}
 }
 
+static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
+{
+	if (!strcmp(dev->prom_name, "i2c"))
+		return 1;
+	return 0;
+}
+
 void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
 {
 	struct linux_prom_registers regs[PROMREG_MAX];
@@ -188,7 +207,8 @@
 		child->next = 0;
 		child->parent = dev;
 		child->bus = dev->bus;
-		fill_ebus_child(node, &regs[0], child);
+		fill_ebus_child(node, &regs[0],
+				child, child_regs_nonstandard(dev));
 
 		while ((node = prom_getsibling(node))) {
 			child->next = ebus_alloc(sizeof(struct linux_ebus_child));
@@ -197,7 +217,8 @@
 			child->next = 0;
 			child->parent = dev;
 			child->bus = dev->bus;
-			fill_ebus_child(node, &regs[0], child);
+			fill_ebus_child(node, &regs[0],
+					child, child_regs_nonstandard(dev));
 		}
 	}
 	printk("]");
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.3.17/linux/arch/sparc64/kernel/entry.S	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc64/kernel/entry.S	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.106 1999/08/02 08:39:34 davem Exp $
+/* $Id: entry.S,v 1.107 1999/08/31 19:25:29 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -477,6 +477,97 @@
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
+
+	/* This is the trap handler entry point for ECC correctable
+	 * errors.  They are corrected, but we listen for the trap
+	 * so that the event can be logged.
+	 *
+	 * Disrupting errors are either:
+	 * 1) single-bit ECC errors during UDB reads to system
+	 *    memory
+	 * 2) data parity errors during write-back events
+	 *
+	 * As far as I can make out from the manual, the CEE trap
+	 * is only for correctable errors during memory read
+	 * accesses by the front-end of the processor.
+	 *
+	 * The code below is only for trap level 1 CEE events,
+	 * as it is the only situation where we can safely record
+	 * and log.  For trap level >1 we just clear the CE bit
+	 * in the AFSR and return.
+	 */
+
+	/* Our trap handling infrastructure allows us to preserve
+	 * two 64-bit values during etrap for arguments to
+	 * subsequent C code.  Therefore we encode the information
+	 * as follows:
+	 *
+	 * value 1) Full 64-bits of AFAR
+	 * value 2) Low 33-bits of AFSR, then bits 33-->42
+	 *          are UDBL error status and bits 43-->52
+	 *          are UDBH error status
+	 */
+	.align	64
+	.globl	cee_trap
+cee_trap:
+	ldxa	[%g0] ASI_AFSR, %g1		! Read AFSR
+	ldxa	[%g0] ASI_AFAR, %g2		! Read AFAR
+	sllx	%g1, 31, %g1			! Clear reserved bits
+	srlx	%g1, 31, %g1			! in AFSR
+
+	/* NOTE: UltraSparc-I/II have high and low UDB error
+	 *       registers, corresponding to the two UDB units
+	 *       present on those chips.  UltraSparc-IIi only
+	 *       has a single UDB, called "SDB" in the manual.
+	 *       For IIi the upper UDB register always reads
+	 *       as zero so for our purposes things will just
+	 *       work with the checks below.
+	 */
+	ldxa	[%g0] ASI_UDBL_ERROR_R, %g3	! Read UDB-Low error status
+	andcc	%g3, (1 << 8), %g4		! Check CE bit
+	sllx	%g3, (64 - 10), %g3		! Clear reserved bits
+	srlx	%g3, (64 - 10), %g3		! in UDB-Low error status
+
+	sllx	%g3, (33 + 0), %g3		! Shift up to encoding area
+	or	%g1, %g3, %g1			! Or it in
+	be,pn	%xcc, 1f			! Branch if CE bit was clear
+	 nop
+	stxa	%g4, [%g0] ASI_UDB_ERROR_W	! Clear CE sticky bit in UDBL
+	membar	#Sync				! Synchronize ASI stores
+1:	mov	0x18, %g5			! Addr of UDB-High error status
+	ldxa	[%g5] ASI_UDBH_ERROR_R, %g3	! Read it
+
+	andcc	%g3, (1 << 8), %g4		! Check CE bit
+	sllx	%g3, (64 - 10), %g3		! Clear reserved bits
+	srlx	%g3, (64 - 10), %g3		! in UDB-High error status
+	sllx	%g3, (33 + 10), %g3		! Shift up to encoding area
+	or	%g1, %g3, %g1			! Or it in
+	be,pn	%xcc, 1f			! Branch if CE bit was clear
+	 nop
+	nop
+
+	stxa	%g4, [%g5] ASI_UDB_ERROR_W	! Clear CE sticky bit in UDBH
+	membar	#Sync				! Synchronize ASI stores
+1:	mov	1, %g5				! AFSR CE bit is
+	sllx	%g5, 20, %g5			! bit 20
+	stxa	%g5, [%g0] ASI_AFSR		! Clear CE sticky bit in AFSR
+	membar	#Sync				! Synchronize ASI stores
+	sllx	%g2, (64 - 41), %g2		! Clear reserved bits
+	srlx	%g2, (64 - 41), %g2		! in latched AFAR
+
+	andn	%g2, 0x0f, %g2			! Finish resv bit clearing
+	mov	%g1, %g4			! Move AFSR+UDB* into save reg
+	mov	%g2, %g5			! Move AFAR into save reg
+	rdpr	%pil, %g2
+	wrpr	%g0, 15, %pil
+	ba,pt	%xcc, etrap_irq
+	 rd	%pc, %g7
+	mov	%l4, %o0
+
+	mov	%l5, %o1
+	call	cee_log
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o2
+	ba,a,pt	%xcc, rtrap_clr_l6
 
 	.globl		__do_privact
 __do_privact:
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.17/linux/arch/sparc64/kernel/ioctl32.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/ioctl32.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.67 1999/08/20 00:27:08 davem Exp $
+/* $Id: ioctl32.c,v 1.68 1999/09/10 05:59:25 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -410,6 +410,7 @@
                 int     ifru_mtu;
                 struct  ifmap32 ifru_map;
                 char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+		char	ifru_newname[IFNAMSIZ];
                 __kernel_caddr_t32 ifru_data;
         } ifr_ifru;
 };
@@ -431,6 +432,8 @@
 	dev = dev_get_by_index(ifr32.ifr_ifindex);
 	if (!dev)
 		return -ENODEV;
+
+	strcpy(ifr32.ifr_name, dev->name);
 
 	err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
 	return (err ? -EFAULT : 0);
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.3.17/linux/arch/sparc64/kernel/pci.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sparc64/kernel/pci.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.1 1999/08/30 10:00:42 davem Exp $
+/* $Id: pci.c,v 1.6 1999/09/08 03:40:41 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -20,45 +20,9 @@
 #include <asm/irq.h>
 #include <asm/ebus.h>
 
-/* This is the base address of IOMMU translated space
- * on PCI bus segments.  This means that any PCI address
- * greater than or equal this value will be translated
- * into a physical address and transferred on the system
- * bus.  Any address less than it will be considered a
- * PCI peer-to-peer transaction.  For example, given a
- * value of 0x80000000:
- *
- *	If a PCI device bus masters the address 0x80001000
- *	then then PCI controller's IOMMU will take the offset
- *	portion (0x1000) and translate that into a physical
- *	address.  The data transfer will be performed to/from
- *	that physical address on the system bus.
- *
- *	If the PCI device bus masters the address 0x00002000
- *	then the PCI controller will not do anything, it will
- *	proceed as a PCI peer-to-peer transfer.
- *
- * This all stems from the fact that PCI drivers in Linux are
- * not conscious of DMA mappings to the extent they need to
- * be for systems like Sparc64 and Alpha which have IOMMU's.
- * Plans are already in the works to fix this.  So what we do
- * at the moment is linearly map all of physical ram with the
- * IOMMU in consistant mode, thus providing the illusion of
- * a simplistic linear DMA mapping scheme to the drivers.
- * This, while it works, is bad for performance (streaming
- * DMA is not used) and limits the amount of total memory we
- * can support (2GB on Psycho, 512MB on Sabre/APB).
- */
-unsigned long pci_dvma_offset = 0x00000000UL;
-
-/* Given a valid PCI dma address (ie. >= pci_dvma_addset) this
- * mask will give you the offset into the DMA space of a
- * PCI bus.
- */
-unsigned long pci_dvma_mask   = 0xffffffffUL;
-
 unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
 unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
+unsigned long pci_memspace_mask = 0xffffffffUL;
 
 #ifndef CONFIG_PCI
 /* A "nop" PCI implementation. */
@@ -123,7 +87,9 @@
 	void (*init)(int);
 } pci_controller_table[] = {
 	{ "SUNW,sabre", sabre_init },
-	{ "SUNW,psycho", psycho_init }
+	{ "pci108e,a000", sabre_init },
+	{ "SUNW,psycho", psycho_init },
+	{ "pci108e,8000", psycho_init }
 };
 #define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
 				  sizeof(pci_controller_table[0]))
@@ -164,6 +130,12 @@
 				       namebuf, sizeof(namebuf));
 		if (len > 0)
 			pci_controller_init(namebuf, len, node);
+		else {
+			len = prom_getproperty(node, "compatible",
+					       namebuf, sizeof(namebuf));
+			if (len > 0)
+				pci_controller_init(namebuf, len, node);
+		}
 		node = prom_getsibling(node);
 		if (!node)
 			break;
@@ -228,6 +200,11 @@
 
 void pcibios_fixup_bus(struct pci_bus *pbus)
 {
+}
+
+int pcibios_assign_resource(struct pci_dev *pdev, int resource)
+{
+	return 0;
 }
 
 char * __init pcibios_setup(char *str)
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/pci_common.c linux/arch/sparc64/kernel/pci_common.c
--- v2.3.17/linux/arch/sparc64/kernel/pci_common.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/pci_common.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: pci_common.c,v 1.2 1999/08/31 09:12:33 davem Exp $
+/* $Id: pci_common.c,v 1.3 1999/09/04 22:26:32 ecd Exp $
  * pci_common.c: PCI controller common support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -20,6 +20,19 @@
 					int *nregs)
 {
 	int node;
+
+	/*
+	 * Return the PBM's PROM node in case we are it's PCI device,
+	 * as the PBM's reg property is different to standard PCI reg
+	 * properties. We would delete this device entry otherwise,
+	 * which confuses XFree86's device probing...
+	 */
+	if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) &&
+	    (pdev->vendor == PCI_VENDOR_ID_SUN) &&
+	    (pdev->device == PCI_DEVICE_ID_SUN_PBM)) {
+		*nregs = 0;
+		return bus_prom_node;
+	}
 
 	node = prom_getchild(bus_prom_node);
 	while (node != 0) {
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/pci_impl.h linux/arch/sparc64/kernel/pci_impl.h
--- v2.3.17/linux/arch/sparc64/kernel/pci_impl.h	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/pci_impl.h	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: pci_impl.h,v 1.1 1999/08/30 10:00:44 davem Exp $
+/* $Id: pci_impl.h,v 1.3 1999/09/10 10:40:44 davem Exp $
  * pci_impl.h: Helper definitions for PCI controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -8,7 +8,7 @@
 #define PCI_IMPL_H
 
 #include <linux/types.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 
 extern spinlock_t pci_controller_lock;
@@ -35,12 +35,12 @@
 extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
 
 /* IOMMU/DVMA initialization. */
-extern unsigned long pci_dvma_offset;
-extern unsigned long pci_dvma_mask;
 #define PCI_DVMA_HASH_NONE	~0UL
-static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr)
+static __inline__ void set_dvma_hash(unsigned long dvma_offset,
+				     unsigned long paddr,
+				     unsigned long daddr)
 {
-	unsigned long dvma_addr = pci_dvma_offset + daddr;
+	unsigned long dvma_addr = dvma_offset + daddr;
 	unsigned long vaddr = (unsigned long)__va(paddr);
 
 	pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr;
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.3.17/linux/arch/sparc64/kernel/pci_psycho.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/pci_psycho.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.2 1999/08/31 09:12:34 davem Exp $
+/* $Id: pci_psycho.c,v 1.4 1999/09/05 09:33:36 ecd Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1312,7 +1312,7 @@
 					     (paddr & IOPTE_PAGE));
 
 			if (!(n & 0xff))
-				set_dvma_hash(paddr, (n << 16));
+				set_dvma_hash(0x80000000, paddr, (n << 16));
 
 			if (++n > (tsbsize * 1024))
 				goto out;
@@ -1338,17 +1338,14 @@
 	switch(tsbsize) {
 	case 8:
 		p->iommu.page_table_map_base = 0xe0000000;
-		pci_dvma_mask = 0x1fffffffUL;
 		control |= PSYCHO_IOMMU_TSBSZ_8K;
 		break;
 	case 16:
 		p->iommu.page_table_map_base = 0xc0000000;
-		pci_dvma_mask = 0x3fffffffUL;
 		control |= PSYCHO_IOMMU_TSBSZ_16K;
 		break;
 	case 32:
 		p->iommu.page_table_map_base = 0x80000000;
-		pci_dvma_mask = 0x7fffffffUL;
 		control |= PSYCHO_IOMMU_TSBSZ_32K;
 		break;
 	default:
@@ -1594,9 +1591,14 @@
 	p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE;
 	printk("PSYCHO: PCI config space at %016lx\n", p->config_space);
 
+	/*
+	 * Psycho's PCI MEM space is mapped to a 2GB aligned area, so
+	 * we need to adjust our MEM space mask.
+	 */
+	pci_memspace_mask = 0x7fffffffUL;
+
 	psycho_controller_hwinit(p);
 
-	pci_dvma_offset = 0x80000000UL;
 	psycho_iommu_init(p, 32);
 
 	is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.3.17/linux/arch/sparc64/kernel/pci_sabre.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/pci_sabre.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.1 1999/08/30 10:00:32 davem Exp $
+/* $Id: pci_sabre.c,v 1.2 1999/09/05 04:58:06 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1121,7 +1121,8 @@
 	sabre_register_error_handlers(p);
 }
 
-static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize)
+static void __init sabre_iommu_init(struct pci_controller_info *p,
+				    int tsbsize, unsigned long dvma_offset)
 {
 	struct linux_mlist_p1275 *mlist;
 	unsigned long tsbbase, i, n, order;
@@ -1142,7 +1143,6 @@
 	for(order = 0;; order++)
 		if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8))
 			break;
-
 	tsbbase = __get_free_pages(GFP_DMA, order);
 	if (!tsbbase) {
 		prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n");
@@ -1200,8 +1200,7 @@
 					     (paddr & IOPTE_PAGE));
 
 			if (!(n & 0xff))
-				set_dvma_hash(paddr, (n << 16));
-
+				set_dvma_hash(dvma_offset, paddr, (n << 16));
 			if (++n > (tsbsize * 1024))
 				goto out;
 
@@ -1225,15 +1224,12 @@
 	control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB);
 	switch(tsbsize) {
 	case 8:
-		pci_dvma_mask = 0x1fffffffUL;
 		control |= IOMMU_TSBSZ_8K;
 		break;
 	case 16:
-		pci_dvma_mask = 0x3fffffffUL;
 		control |= IOMMU_TSBSZ_16K;
 		break;
 	case 32:
-		pci_dvma_mask = 0x7fffffffUL;
 		control |= IOMMU_TSBSZ_32K;
 		break;
 	default:
@@ -1463,8 +1459,7 @@
 			prom_halt();
 	}
 
-	pci_dvma_offset = vdma[0];
-	sabre_iommu_init(p, tsbsize);
+	sabre_iommu_init(p, tsbsize, vdma[0]);
 
 	printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
 
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/power.c linux/arch/sparc64/kernel/power.c
--- v2.3.17/linux/arch/sparc64/kernel/power.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/power.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: power.c,v 1.2 1999/08/31 04:39:38 davem Exp $
+/* $Id: power.c,v 1.4 1999/08/31 18:22:05 davem Exp $
  * power.c: Power management driver.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.3.17/linux/arch/sparc64/kernel/signal.c	Fri Aug  6 11:58:00 1999
+++ linux/arch/sparc64/kernel/signal.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.44 1999/08/04 07:04:13 jj Exp $
+/*  $Id: signal.c,v 1.45 1999/09/06 08:21:59 jj Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -228,7 +228,7 @@
 
 struct rt_signal_frame {
 	struct sparc_stackf	ss;
-	siginfo_t	info;
+	siginfo_t		info;
 	struct pt_regs		regs;
 	__siginfo_fpu_t *	fpu_save;
 	stack_t			stack;
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.3.17/linux/arch/sparc64/kernel/smp.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sparc64/kernel/smp.c	Wed Sep  8 11:59:00 1999
@@ -14,6 +14,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/head.h>
 #include <asm/ptrace.h>
@@ -23,7 +24,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
-#include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.17/linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Aug  6 11:58:00 1999
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.62 1999/08/06 01:42:48 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.64 1999/09/05 09:33:38 ecd Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -190,10 +190,9 @@
 #endif
 #if CONFIG_PCI
 EXPORT_SYMBOL(ebus_chain);
-EXPORT_SYMBOL(pci_dvma_offset);
-EXPORT_SYMBOL(pci_dvma_mask);
 EXPORT_SYMBOL(pci_dvma_v2p_hash);
 EXPORT_SYMBOL(pci_dvma_p2v_hash);
+EXPORT_SYMBOL(pci_memspace_mask);
 EXPORT_SYMBOL(empty_zero_page);
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- v2.3.17/linux/arch/sparc64/kernel/trampoline.S	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/kernel/trampoline.S	Fri Sep 10 11:06:19 1999
@@ -1,8 +1,10 @@
-/* $Id: trampoline.S,v 1.9 1999/05/25 16:53:12 jj Exp $
+/* $Id: trampoline.S,v 1.10 1999/09/10 10:40:48 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
+
+#include <linux/config.h>
 
 #include <asm/head.h>
 #include <asm/asi.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.3.17/linux/arch/sparc64/kernel/traps.c	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc64/kernel/traps.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.61 1999/07/30 09:35:32 davem Exp $
+/* $Id: traps.c,v 1.62 1999/08/31 19:25:35 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -393,6 +393,124 @@
 	lock_kernel();
 	force_sig(SIGSEGV, current);
 	unlock_kernel();
+}
+
+static char ecc_syndrome_table[] = {
+	0x4c, 0x40, 0x41, 0x48, 0x42, 0x48, 0x48, 0x49,
+	0x43, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4a,
+	0x44, 0x48, 0x48, 0x20, 0x48, 0x39, 0x4b, 0x48,
+	0x48, 0x25, 0x31, 0x48, 0x28, 0x48, 0x48, 0x2c,
+	0x45, 0x48, 0x48, 0x21, 0x48, 0x3d, 0x04, 0x48,
+	0x48, 0x4b, 0x35, 0x48, 0x2d, 0x48, 0x48, 0x29,
+	0x48, 0x00, 0x01, 0x48, 0x0a, 0x48, 0x48, 0x4b,
+	0x0f, 0x48, 0x48, 0x4b, 0x48, 0x49, 0x49, 0x48,
+	0x46, 0x48, 0x48, 0x2a, 0x48, 0x3b, 0x27, 0x48,
+	0x48, 0x4b, 0x33, 0x48, 0x22, 0x48, 0x48, 0x2e,
+	0x48, 0x19, 0x1d, 0x48, 0x1b, 0x4a, 0x48, 0x4b,
+	0x1f, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
+	0x48, 0x4b, 0x24, 0x48, 0x07, 0x48, 0x48, 0x36,
+	0x4b, 0x48, 0x48, 0x3e, 0x48, 0x30, 0x38, 0x48,
+	0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x16, 0x48,
+	0x48, 0x12, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
+	0x47, 0x48, 0x48, 0x2f, 0x48, 0x3f, 0x4b, 0x48,
+	0x48, 0x06, 0x37, 0x48, 0x23, 0x48, 0x48, 0x2b,
+	0x48, 0x05, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x32,
+	0x26, 0x48, 0x48, 0x3a, 0x48, 0x34, 0x3c, 0x48,
+	0x48, 0x11, 0x15, 0x48, 0x13, 0x4a, 0x48, 0x4b,
+	0x17, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
+	0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x1e, 0x48,
+	0x48, 0x1a, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
+	0x48, 0x08, 0x0d, 0x48, 0x02, 0x48, 0x48, 0x49,
+	0x03, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x4b, 0x48,
+	0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x10, 0x48,
+	0x48, 0x14, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
+	0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x18, 0x48,
+	0x48, 0x1c, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
+	0x4a, 0x0c, 0x09, 0x48, 0x0e, 0x48, 0x48, 0x4b,
+	0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
+};
+
+/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status
+ * in the following format.  The AFAR is left as is, with
+ * reserved bits cleared, and is a raw 40-bit physical
+ * address.
+ */
+#define CE_STATUS_UDBH_UE		(1UL << (43 + 9))
+#define CE_STATUS_UDBH_CE		(1UL << (43 + 8))
+#define CE_STATUS_UDBH_ESYNDR		(0xffUL << 43)
+#define CE_STATUS_UDBH_SHIFT		43
+#define CE_STATUS_UDBL_UE		(1UL << (33 + 9))
+#define CE_STATUS_UDBL_CE		(1UL << (33 + 8))
+#define CE_STATUS_UDBL_ESYNDR		(0xffUL << 33)
+#define CE_STATUS_UDBL_SHIFT		33
+#define CE_STATUS_AFSR_MASK		(0x1ffffffffUL)
+#define CE_STATUS_AFSR_ME		(1UL << 32)
+#define CE_STATUS_AFSR_PRIV		(1UL << 31)
+#define CE_STATUS_AFSR_ISAP		(1UL << 30)
+#define CE_STATUS_AFSR_ETP		(1UL << 29)
+#define CE_STATUS_AFSR_IVUE		(1UL << 28)
+#define CE_STATUS_AFSR_TO		(1UL << 27)
+#define CE_STATUS_AFSR_BERR		(1UL << 26)
+#define CE_STATUS_AFSR_LDP		(1UL << 25)
+#define CE_STATUS_AFSR_CP		(1UL << 24)
+#define CE_STATUS_AFSR_WP		(1UL << 23)
+#define CE_STATUS_AFSR_EDP		(1UL << 22)
+#define CE_STATUS_AFSR_UE		(1UL << 21)
+#define CE_STATUS_AFSR_CE		(1UL << 20)
+#define CE_STATUS_AFSR_ETS		(0xfUL << 16)
+#define CE_STATUS_AFSR_ETS_SHIFT	16
+#define CE_STATUS_AFSR_PSYND		(0xffffUL << 0)
+#define CE_STATUS_AFSR_PSYND_SHIFT	0
+
+/* Layout of Ecache TAG Parity Syndrome of AFSR */
+#define AFSR_ETSYNDROME_7_0		0x1UL /* E$-tag bus bits  <7:0> */
+#define AFSR_ETSYNDROME_15_8		0x2UL /* E$-tag bus bits <15:8> */
+#define AFSR_ETSYNDROME_21_16		0x4UL /* E$-tag bus bits <21:16> */
+#define AFSR_ETSYNDROME_24_22		0x8UL /* E$-tag bus bits <24:22> */
+
+static char *syndrome_unknown = "<Unknown>";
+
+asmlinkage void cee_log(unsigned long ce_status,
+			unsigned long afar,
+			struct pt_regs *regs)
+{
+	char memmod_str[64];
+	char *p;
+	unsigned short scode, udb_reg;
+
+	printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
+	       "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n",
+	       smp_processor_id(),
+	       (ce_status & CE_STATUS_AFSR_MASK),
+	       afar,
+	       ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL),
+	       ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL));
+
+	udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL);
+	if (udb_reg & (1 << 8)) {
+		scode = ecc_syndrome_table[udb_reg & 0xff];
+		if (prom_getunumber(scode, afar,
+				    memmod_str, sizeof(memmod_str)) == -1)
+			p = syndrome_unknown;
+		else
+			p = memmod_str;
+		printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] "
+		       "Memory Module \"%s\"\n",
+		       smp_processor_id(), scode, p);
+	}
+
+	udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL);
+	if (udb_reg & (1 << 8)) {
+		scode = ecc_syndrome_table[udb_reg & 0xff];
+		if (prom_getunumber(scode, afar,
+				    memmod_str, sizeof(memmod_str)) == -1)
+			p = syndrome_unknown;
+		else
+			p = memmod_str;
+		printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] "
+		       "Memory Module \"%s\"\n",
+		       smp_processor_id(), scode, p);
+	}
 }
 
 void do_fpe_common(struct pt_regs *regs)
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.3.17/linux/arch/sparc64/kernel/ttable.S	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/kernel/ttable.S	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.28 1999/03/29 12:38:10 jj Exp $
+/* $Id: ttable.S,v 1.29 1999/08/31 19:25:37 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -57,7 +57,7 @@
 tl0_ivec:	TRAP_IVEC
 tl0_paw:	TRAP(do_paw)
 tl0_vaw:	TRAP(do_vaw)
-tl0_cee:	TRAP(do_cee)
+tl0_cee:	TRAP_NOSAVE(cee_trap)
 tl0_iamiss:
 #include	"itlb_base.S"
 tl0_damiss:
@@ -202,7 +202,7 @@
 tl1_ivec:	TRAP_IVEC
 tl1_paw:	TRAPTL1(do_paw_tl1)
 tl1_vaw:	TRAPTL1(do_vaw_tl1)
-tl1_cee:	TRAPTL1(do_cee_tl1)
+tl1_cee:	TRAPTL1_CEE
 tl1_iamiss:	BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67)
 tl1_damiss:
 #include	"dtlb_backend.S"
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/lib/PeeCeeI.c linux/arch/sparc64/lib/PeeCeeI.c
--- v2.3.17/linux/arch/sparc64/lib/PeeCeeI.c	Thu Sep  4 12:54:48 1997
+++ linux/arch/sparc64/lib/PeeCeeI.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: PeeCeeI.c,v 1.3 1997/08/28 23:59:52 davem Exp $
+/* $Id: PeeCeeI.c,v 1.4 1999/09/06 01:17:35 davem Exp $
  * PeeCeeI.c: The emerging standard...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -9,6 +9,7 @@
 #ifdef CONFIG_PCI
 
 #include <asm/io.h>
+#include <asm/byteorder.h>
 
 void outsb(unsigned long addr, const void *src, unsigned long count)
 {
@@ -21,25 +22,29 @@
 void outsw(unsigned long addr, const void *src, unsigned long count)
 {
 	if(count) {
-		const u16 *ps = src;
-		const u32 *pi;
+		u16 *ps = (u16 *)src;
+		u32 *pi;
 
 		if(((u64)src) & 0x2) {
-			outw(*ps++, addr);
+			u16 val = le16_to_cpup(ps);
+			outw(val, addr);
+			ps++;
 			count--;
 		}
-		pi = (const u32 *)ps;
+		pi = (u32 *)ps;
 		while(count >= 2) {
-			u32 w;
+			u32 w = le32_to_cpup(pi);
 
-			w = *pi++;
+			pi++;
+			outw(w >> 0, addr);
 			outw(w >> 16, addr);
-			outw(w, addr);
 			count -= 2;
 		}
-		ps = (const u16 *)pi;
-		if(count)
-			outw(*ps, addr);
+		ps = (u16 *)pi;
+		if(count) {
+			u16 val = le16_to_cpup(ps);
+			outw(val, addr);
+		}
 	}
 }
 
@@ -47,60 +52,71 @@
 {
 	if(count) {
 		if((((u64)src) & 0x3) == 0) {
-			const u32 *p = src;
-			while(count--)
-				outl(*p++, addr);
+			u32 *p = (u32 *)src;
+			while(count--) {
+				u32 val = cpu_to_le32p(p);
+				outl(val, addr);
+				p++;
+			}
 		} else {
-			const u8 *pb;
-			const u16 *ps = src;
+			u8 *pb;
+			u16 *ps = (u16 *)src;
 			u32 l = 0, l2;
-			const u32 *pi;
+			u32 *pi;
 
 			switch(((u64)src) & 0x3) {
 			case 0x2:
 				count -= 1;
-				l = *ps++;
-				pi = (const u32 *)ps;
+				l = cpu_to_le16p(ps) << 16;
+				ps++;
+				pi = (u32 *)ps;
 				while(count--) {
-					l2 = *pi++;
-					outl(((l <<16) | (l2 >> 16)), addr);
+					l2 = cpu_to_le32p(pi);
+					pi++;
+					outl(((l >> 16) | (l2 << 16)), addr);
 					l = l2;
 				}
-				ps = (const u16 *)pi;
-				outl(((l << 16) | (*ps >> 16)), addr);
+				ps = (u16 *)pi;
+				l2 = cpu_to_le16p(ps);
+				outl(((l >> 16) | (l2 << 16)), addr);
 				break;
 
 			case 0x1:
 				count -= 1;
-				pb = src;
-				l = (*pb++ << 16);
-				ps = (const u16 *)pb;
-				l |= *ps++;
-				pi = (const u32 *)ps;
+				pb = (u8 *)src;
+				l = (*pb++ << 8);
+				ps = (u16 *)pb;
+				l2 = cpu_to_le16p(ps);
+				ps++;
+				l |= (l2 << 16);
+				pi = (u32 *)ps;
 				while(count--) {
-					l2 = *pi++;
-					outl(((l << 8) | (l2 >> 24)), addr);
+					l2 = cpu_to_le32p(pi);
+					pi++;
+					outl(((l >> 8) | (l2 << 24)), addr);
 					l = l2;
 				}
-				pb = (const u8 *)pi;
-				outl(((l << 8) | (*pb >> 24)), addr);
+				pb = (u8 *)pi;
+				outl(((l >> 8) | (*pb << 24)), addr);
 				break;
 
 			case 0x3:
 				count -= 1;
-				pb = src;
-				l = (*pb++ >> 24);
-				pi = (const u32 *)pb;
-				while(count--) {
-					l2 = *pi++;
-					outl(((l << 24) | (l2 >> 8)), addr);
+				pb = (u8 *)src;
+				l = (*pb++ << 24);
+				pi = (u32 *)pb;
+				while(count--) {
+					l2 = cpu_to_le32p(pi);
+					pi++;
+					outl(((l >> 24) | (l2 << 8)), addr);
 					l = l2;
 				}
-				ps = (const u16 *)pi;
-				l2 = (*ps++ << 16);
-				pb = (const u8 *)ps;
-				l2 |= (*pb << 8);
-				outl(((l << 24) | (l2 >> 8)), addr);
+				ps = (u16 *)pi;
+				l2 = cpu_to_le16p(ps);
+				ps++;
+				pb = (u8 *)ps;
+				l2 |= (*pb << 16);
+				outl(((l >> 24) | (l2 << 8)), addr);
 				break;
 			}
 		}
@@ -122,7 +138,7 @@
 			w  = (inb(addr) << 24);
 			w |= (inb(addr) << 16);
 			w |= (inb(addr) << 8);
-			w |= inb(addr);
+			w |= (inb(addr) << 0);
 			*pi++ = w;
 			count -= 4;
 		}
@@ -139,21 +155,21 @@
 		u32 *pi;
 
 		if(((unsigned long)ps) & 0x2) {
-			*ps++ = inw(addr);
+			*ps++ = le16_to_cpu(inw(addr));
 			count--;
 		}
 		pi = (u32 *)ps;
 		while(count >= 2) {
 			u32 w;
 
-			w  = (inw(addr) << 16);
-			w |= inw(addr);
+			w  = (le16_to_cpu(inw(addr)) << 16);
+			w |= (le16_to_cpu(inw(addr)) << 0);
 			*pi++ = w;
 			count -= 2;
 		}
 		ps = (u16 *)pi;
 		if(count)
-			*ps = inw(addr);
+			*ps = le16_to_cpu(inw(addr));
 	}
 }
 
@@ -163,7 +179,7 @@
 		if((((unsigned long)dst) & 0x3) == 0) {
 			u32 *pi = dst;
 			while(count--)
-				*pi++ = inl(addr);
+				*pi++ = le32_to_cpu(inl(addr));
 		} else {
 			u32 l = 0, l2, *pi;
 			u16 *ps;
@@ -173,47 +189,48 @@
 			case 0x2:
 				ps = dst;
 				count -= 1;
-				l = inl(addr);
-				*ps++ = (l >> 16);
+				l = le32_to_cpu(inl(addr));
+				*ps++ = l;
 				pi = (u32 *)ps;
 				while(count--) {
-					l2 = inl(addr);
+					l2 = le32_to_cpu(inl(addr));
 					*pi++ = (l << 16) | (l2 >> 16);
 					l = l2;
 				}
 				ps = (u16 *)pi;
-				*ps = (l << 16);
+				*ps = l;
 				break;
 
 			case 0x1:
 				pb = dst;
 				count -= 1;
-				*pb++ = (l >> 24);
+				l = le32_to_cpu(inl(addr));
+				*pb++ = l >> 24;
 				ps = (u16 *)pb;
-				*ps++ = (l >> 8);
+				*ps++ = ((l >> 8) & 0xffff);
 				pi = (u32 *)ps;
 				while(count--) {
-					l2 = inl(addr);
-					*pi++ = ((l << 24) | (l2 >> 8));
+					l2 = le32_to_cpu(inl(addr));
+					*pi++ = (l << 24) | (l2 >> 8);
 					l = l2;
 				}
 				pb = (u8 *)pi;
-				*pb = (l >> 8);
+				*pb = l;
 				break;
 
 			case 0x3:
 				pb = (u8 *)dst;
 				count -= 1;
-				l = inl(addr);
+				l = le32_to_cpu(inl(addr));
 				*pb++ = l >> 24;
 				pi = (u32 *)pb;
 				while(count--) {
-					l2 = inl(addr);
-					*pi++ = ((l >> 24) | (l2 << 8));
+					l2 = le32_to_cpu(inl(addr));
+					*pi++ = (l << 8) | (l2 >> 24);
 					l = l2;
 				}
 				ps = (u16 *)pi;
-				*ps++ = l >> 8;
+				*ps++ = ((l >> 8) & 0xffff);
 				pb = (u8 *)ps;
 				*pb = l;
 				break;
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c
--- v2.3.17/linux/arch/sparc64/lib/debuglocks.c	Tue Oct 27 09:52:20 1998
+++ linux/arch/sparc64/lib/debuglocks.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: debuglocks.c,v 1.2 1998/10/13 09:07:27 davem Exp $
+/* $Id: debuglocks.c,v 1.3 1999/09/10 10:40:50 davem Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
@@ -6,8 +6,8 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 #ifdef __SMP__
 
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.3.17/linux/arch/sparc64/mm/init.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/mm/init.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.134 1999/08/31 06:54:58 davem Exp $
+/*  $Id: init.c,v 1.135 1999/09/06 22:55:10 ecd Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -1477,4 +1477,6 @@
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
+	val->totalbig = 0;
+	val->freebig = 0;
 }
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.3.17/linux/arch/sparc64/mm/ultra.S	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc64/mm/ultra.S	Fri Sep 10 11:06:19 1999
@@ -1,8 +1,10 @@
-/* $Id: ultra.S,v 1.33 1999/08/02 08:39:49 davem Exp $
+/* $Id: ultra.S,v 1.34 1999/09/10 10:40:51 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
+
+#include <linux/config.h>
 
 #include <asm/asi.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c
--- v2.3.17/linux/arch/sparc64/prom/misc.c	Wed Mar 10 16:53:37 1999
+++ linux/arch/sparc64/prom/misc.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.14 1998/12/18 10:01:59 davem Exp $
+/* $Id: misc.c,v 1.15 1999/08/31 19:25:41 davem Exp $
  * misc.c:  Miscellaneous prom functions that don't belong
  *          anywhere else.
  *
@@ -125,15 +125,37 @@
 /* This is only used internally below. */
 static int prom_get_mmu_ihandle(void)
 {
-	int node;
-	int ret;
+	static int mmu_ihandle_cache = 0;
+	int node, ret;
+
+	if (mmu_ihandle_cache != 0)
+		return mmu_ihandle_cache;
 
 	node = prom_finddevice("/chosen");
 	ret = prom_getint(node, "mmu");
-	if(ret == -1 || ret == 0) {
-		prom_printf("PROMLIB: Fatal error, cannot get mmu ihandle.\n");
-		prom_halt();
-	}
+	if(ret == -1 || ret == 0)
+		mmu_ihandle_cache = -1;
+	else
+		mmu_ihandle_cache = ret;
+
+	return ret;
+}
+
+static int prom_get_memory_ihandle(void)
+{
+	static int memory_ihandle_cache = 0;
+	int node, ret;
+
+	if (memory_ihandle_cache != 0)
+		return memory_ihandle_cache;
+
+	node = prom_finddevice("/chosen");
+	ret = prom_getint(node, "memory");
+	if (ret == -1 || ret == 0)
+		memory_ihandle_cache = -1;
+	else
+		memory_ihandle_cache = ret;
+
 	return ret;
 }
 
@@ -197,12 +219,18 @@
  * etched into the motherboard next to the SIMM slot
  * in question.
  */
-int prom_getunumber(unsigned long phys_lo, unsigned long phys_hi,
+int prom_getunumber(int syndrome_code,
+		    unsigned long phys_addr,
 		    char *buf, int buflen)
 {
-	return p1275_cmd("SUNW,get-unumber",
-			 (P1275_ARG(2, P1275_ARG_OUT_BUF) | P1275_INOUT(4, 1)),
-			 phys_lo, phys_hi, buf, buflen);
+	return p1275_cmd("call-method",
+			 (P1275_ARG(0, P1275_ARG_IN_STRING)	|
+			  P1275_ARG(3, P1275_ARG_OUT_BUF)	|
+			  P1275_ARG(5, P1275_ARG_IN_64B)	|
+			  P1275_INOUT(8, 2)),
+			 "SUNW,get-unumber", prom_get_memory_ihandle(),
+			 buflen, buf, P1275_SIZE(buflen),
+			 0, phys_addr, syndrome_code);
 }
 
 /* Power management extensions. */
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c
--- v2.3.17/linux/arch/sparc64/prom/p1275.c	Mon Aug  2 22:07:16 1999
+++ linux/arch/sparc64/prom/p1275.c	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.16 1999/08/02 12:05:57 jj Exp $
+/* $Id: p1275.c,v 1.18 1999/09/10 10:40:53 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -9,13 +9,13 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
 #include <asm/pstate.h>
-#include <asm/spinlock.h>
 
 struct {
 	long prom_callback;			/* 0x00 */
@@ -320,6 +320,10 @@
 		case P1275_ARG_NUMBER:
 			p1275buf.prom_args[i + 3] =
 						(unsigned)va_arg(list, long);
+			break;
+		case P1275_ARG_IN_64B:
+			p1275buf.prom_args[i + 3] =
+				va_arg(list, unsigned long);
 			break;
 		case P1275_ARG_IN_STRING:
 			strcpy (p, va_arg(list, char *));
diff -u --recursive --new-file v2.3.17/linux/arch/sparc64/solaris/timod.c linux/arch/sparc64/solaris/timod.c
--- v2.3.17/linux/arch/sparc64/solaris/timod.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/solaris/timod.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: timod.c,v 1.3 1999/08/02 12:06:01 jj Exp $
+/* $Id: timod.c,v 1.4 1999/09/01 08:07:47 davem Exp $
  * timod.c: timod emulation.
  *
  * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/Config.in linux/drivers/atm/Config.in
--- v2.3.17/linux/drivers/atm/Config.in	Thu Aug 26 13:05:34 1999
+++ linux/drivers/atm/Config.in	Wed Sep  8 11:14:31 1999
@@ -1,6 +1,7 @@
 #
 # ATM device configuration
 #
+mainmenu_option next_comment
 comment 'ATM drivers'
 if [ "$CONFIG_INET" = "y" ]; then
   tristate 'ATM over TCP' CONFIG_ATM_TCP y
@@ -43,3 +44,4 @@
     bool '  Enable debugging messages' CONFIG_ATM_HORIZON_DEBUG
   fi
 fi
+endmenu
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/Makefile linux/drivers/atm/Makefile
--- v2.3.17/linux/drivers/atm/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/drivers/atm/Makefile	Wed Sep  8 11:14:31 1999
@@ -12,19 +12,21 @@
 
 ifeq ($(CONFIG_ATM_ENI),y)
 L_OBJS += eni.o
-LX_OBJS += suni.o
+NEED_SUNI_LX = suni.o
 else
   ifeq ($(CONFIG_ATM_ENI),m)
   M_OBJS += eni.o
-  MX_OBJS += suni.o
+  NEED_SUNI_MX = suni.o
   endif
 endif
 
 ifeq ($(CONFIG_ATM_ZATM),y)
-LX_OBJS += zatm.o uPD98402.o
+L_OBJS += zatm.o
+LX_OBJS += uPD98402.o
 else
   ifeq ($(CONFIG_ATM_ZATM),m)
-  MX_OBJS += zatm.o uPD98402.o
+  M_OBJS += zatm.o
+  MX_OBJS += uPD98402.o
   endif
 endif
 
@@ -39,13 +41,13 @@
 ifeq ($(CONFIG_ATM_NICSTAR),y)
 L_OBJS += nicstar.o
   ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
-  LX_OBJS += suni.o
+  NEED_SUNI_LX = suni.o
   endif
 else
   ifeq ($(CONFIG_ATM_NICSTAR),m)
   M_OBJS += nicstar.o
     ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
-    MX_OBJS += suni.o
+    NEED_SUNI_MX = suni.o
     endif
   endif
 endif
@@ -64,6 +66,12 @@
   ifeq ($(CONFIG_ATM_AMBASSADOR),m)
   M_OBJS += ambassador.o
   endif
+endif
+
+ifeq ($(NEED_SUNI_LX),)
+  MX_OBJS += $(NEED_SUNI_MX)
+else
+  LX_OBJS += $(NEED_SUNI_LX)
 endif
 
 ifeq ($(CONFIG_ATM_TCP),y)
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c
--- v2.3.17/linux/drivers/atm/ambassador.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/atm/ambassador.c	Wed Sep  8 11:14:31 1999
@@ -20,11 +20,6 @@
   system and in the file COPYING in the Linux kernel source.
 */
 
-/*
-  IMPORTANT NOTE: Madge Networks does not license the microcode for
-  this driver under the GPL. See the .data file for the licence.
-*/
-
 /* * dedicated to the memory of Graham Gordon 1971-1998 * */
 
 #include <linux/module.h>
@@ -44,7 +39,7 @@
 
 #define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
 #define description_string "Madge ATM Ambassador driver"
-#define version_string "1.1"
+#define version_string "1.2"
 
 static inline void __init show_version (void) {
   printk ("%s version %s\n", description_string, version_string);
@@ -122,11 +117,11 @@
   
   The queue pairs work as follows: one queue is for supply to the
   adapter, items in it are pending and are owned by the adapter; the
-  other is the for return from the adapter, items in it have been
-  dealt with by the adapter. The host adds items to the supply (TX
-  descriptors and free RX buffer descriptors) and removes items from
-  the return (TX and RX completions). The adapter deals with out of
-  order completions.
+  other is the queue for return from the adapter, items in it have
+  been dealt with by the adapter. The host adds items to the supply
+  (TX descriptors and free RX buffer descriptors) and removes items
+  from the return (TX and RX completions). The adapter deals with out
+  of order completions.
   
   Interrupts (card to host) and the doorbell (host to card) are used
   for signalling.
@@ -170,25 +165,26 @@
 
     delay/spacing = latency = (20+2)/3 = 7 (buffers)  (rounding up)
     
-  The 20us delay assumes that there is no need to touch disk; if we
-  need touch disk to get buffers we are going to drop frames anyway.
-   
+  The 20us delay assumes that there is no need to sleep; if we need to
+  sleep to get buffers we are going to drop frames anyway.
+  
   In fact, each pool should have enough buffers to support the
   simultaneous reassembly of a separate frame on each VC and cope with
-  the case in which large frames arrive with round robin cell arrivals
-  on each VC.
-   
+  the case in which frames complete in round robin cell fashion on
+  each VC.
+  
   Only one frame can complete at each cell arrival, so if "n" VCs are
   open, the worst case is to have them all complete frames together
   followed by all starting new frames together.
   
-    min number of buffers = n + delay/spacing
+    desired number of buffers = n + delay/spacing
     
   These are the extreme requirements, however, they are "n+k" for some
   "k" so we have only the constant to choose. This is the argument
-  rx_lats which current defaults at 3.
+  rx_lats which current defaults to 7.
   
-  Actually, "n ? n+k : 0" is better and this is what is implemented.
+  Actually, "n ? n+k : 0" is better and this is what is implemented,
+  subject to the limit given by the pool size.
   
   4. Driver locking
   
@@ -202,7 +198,7 @@
   and close functions. There are three reasons for a lock: 1. we need
   to do atomic rate reservation and release (not used yet), 2. Opening
   sometimes involves two adapter commands which must not be separated
-  by another command on the same VC, 3. the changes in RX pool size
+  by another command on the same VC, 3. the changes to RX pool size
   must be atomic. The lock needs to work over context switches, so we
   use a semaphore.
   
@@ -229,12 +225,12 @@
   The PLX likes to prefetch; if reading up to 4 u32 past the end of
   each TX fragment is not a problem, then TX can be made to go a
   little faster by passing a flag at init that disables a prefetch
-  workaround. We do not pass this flag.
+  workaround. We do not pass this flag. (new microcode only)
   
   Now we:
-  . Note that skb_alloc rounds up size to a 16byte boundary.  
-  . Ensure all areas must not traverse 4MB boundaries.
-  . Ensure all areas must not start at a E00000xx bus address.
+  . Note that alloc_skb rounds up size to a 16byte boundary.  
+  . Ensure all areas do not traverse 4MB boundaries.
+  . Ensure all areas do not start at a E00000xx bus address.
   (I cannot be certain, but this may always hold with Linux)
   . Make all failures cause a loud message.
   . Discard non-conforming SKBs (causes TX failure or RX fill delay).
@@ -321,13 +317,15 @@
 static unsigned int cmds = 8;
 static unsigned int txs = 32;
 static unsigned int rxs[NUM_RX_POOLS] = { 64, 64, 64, 64 };
-static unsigned int rxs_bs[NUM_RX_POOLS] = { 2500, 5000, 10000, 20000 };
+static unsigned int rxs_bs[NUM_RX_POOLS] = { 4080, 12240, 36720, 65535 };
 static unsigned int rx_lats = 7;
 static unsigned char pci_lat = 0;
 
 /********** access to adapter **********/
 
-static inline void wr_mem (const amb_dev * dev, u32 * addr, u32 data) {
+static const amb_mem * const mem = 0;
+
+static inline void wr_mem (const amb_dev * dev, const u32 * addr, u32 data) {
   u32 be = cpu_to_be32 (data);
   PRINTD (DBG_FLOW|DBG_REGS, "wr: %p <- %08x b[%08x]", addr, data, be);
 #ifdef AMB_MMIO
@@ -337,7 +335,7 @@
 #endif
 }
 
-static inline u32 rd_mem (const amb_dev * dev, u32 * addr) {
+static inline u32 rd_mem (const amb_dev * dev, const u32 * addr) {
 #ifdef AMB_MMIO
   u32 be = dev->membase[addr - (u32 *) 0];
 #else
@@ -499,7 +497,7 @@
 	  
 	} else {
 	  // someone fix this (message), please!
-	  PRINTD (DBG_INFO|DBG_RX, "dropped thanks to atm_charge (vc %hu)", vc);
+	  PRINTD (DBG_INFO|DBG_RX, "dropped thanks to atm_charge (vc %hu, truesize %u)", vc, skb->truesize);
 	  // drop stats incremented in atm_charge
 	}
 	
@@ -755,7 +753,7 @@
   if (rxq->pending > rxq->buffers_wanted) {
     command cmd;
     cmd.request = cpu_to_be32 (SRB_FLUSH_BUFFER_Q);
-    cmd.args.flush.flags = cpu_to_be16 (pool << SRB_POOL_SHIFT);
+    cmd.args.flush.flags = cpu_to_be32 (pool << SRB_POOL_SHIFT);
     while (command_do (dev, &cmd))
       schedule();
     /* the pool may also be emptied via the interrupt handler */
@@ -792,7 +790,7 @@
   rxq = &dev->rxq[pool];
   while (rxq->pending < rxq->maximum && rxq->pending < rxq->buffers_wanted) {
     
-    struct sk_buff * skb = alloc_skb (rxq->buffer_size + RX_FUDGE, priority);
+    struct sk_buff * skb = alloc_skb (rxq->buffer_size, priority);
     if (!skb) {
       PRINTD (DBG_SKB|DBG_POOL, "failed to allocate skb for RX pool %hu", pool);
       return;
@@ -880,11 +878,9 @@
   
   while (irq_ok_old != irq_ok && irq_ok < 100) {
     unsigned char pool;
-#ifdef DEBUG_AMBASSADOR
-    u32 ints = rd_mem (dev, &mem->interrupt);
-#endif
+    PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u",
+	    rd_mem (dev, &mem->interrupt), irq_ok);
     wr_mem (dev, &mem->interrupt, -1);
-    PRINTD (DBG_IRQ, "FYI: interrupt was %08x, work %u", ints, irq_ok);
     irq_ok_old = irq_ok;
     for (pool = 0; pool < NUM_RX_POOLS; ++pool)
       while (!rx_take (dev, pool))
@@ -970,9 +966,9 @@
 /********** make rate (not quite as much fun as Horizon) **********/
 
 static unsigned int make_rate (unsigned int rate, rounding r,
-			u16 * bits, unsigned int * actual) {
-  unsigned char exp = 0; /* silence gcc */
-  unsigned int man = 0;
+			       u16 * bits, unsigned int * actual) {
+  unsigned char exp = -1; // hush gcc
+  unsigned int man = -1;  // hush gcc
   
   PRINTD (DBG_FLOW|DBG_QOS, "make_rate %u", rate);
   
@@ -987,12 +983,20 @@
   // find position of top bit, this gives e
   // remove top bit and shift (rounding if feeling clever) by 9-e
   
-  // XXX fix me to work with larger ints
-  
   // ucode bug: please don't set bit 14! 0 not representable
   
-  if (rate) {
-    // non-zero rate
+  if (rate > 0xffc00000U) {
+    // larger than largest representable rate
+    
+    if (r == round_up) {
+	return -EINVAL;
+    } else {
+      exp = 31;
+      man = 511;
+    }
+    
+  } else if (rate) {
+    // representable rate
     
     exp = 31;
     man = rate;
@@ -1007,13 +1011,14 @@
     // rate = (2^31+(man-2^31))*2^(exp-31)
     // rate = (1+(man-2^31)/2^31)*2^exp
     man = man<<1;
+    man &= 0xffffffffU; // a nop on 32-bit systems
     // rate = (1+man/2^32)*2^exp
     
     // exp is in the range 0 to 31, man is in the range 0 to 2^32-1
     // time to lose significance... we want m in the range 0 to 2^9-1
     // rounding presents a minor problem... we first decide which way
-    // we are rounding (based on given rounding direction and the bits
-    // of the mantissa that are to be discarded).
+    // we are rounding (based on given rounding direction and possibly
+    // the bits of the mantissa that are to be discarded).
     
     switch (r) {
       case round_down: {
@@ -1026,13 +1031,9 @@
 	if (man & (-1>>9)) {
 	  man = (man>>(32-9)) + 1;
 	  if (man == (1<<9)) {
-	    // check for round up outside of range
-	    if (exp == 31) {
-	      return -EINVAL;
-	    } else {
-	      man = 0;
-	      exp += 1;
-	    }
+	    // no need to check for round up outside of range
+	    man = 0;
+	    exp += 1;
 	  }
 	} else {
 	  man = (man>>(32-9));
@@ -1043,14 +1044,10 @@
 	// check msb that we are discarding
 	if (man & (1<<(32-9-1))) {
 	  man = (man>>(32-9)) + 1;
-	  // if rounding up would go out of range, just stay at top
 	  if (man == (1<<9)) {
-	    if (exp == 31) {
-	      man -= 1;
-	    } else {
-	      man = 0;
-	      exp += 1;
-	    }
+	    // no need to check for round up outside of range
+	    man = 0;
+	    exp += 1;
 	  }
 	} else {
 	  man = (man>>(32-9));
@@ -1060,19 +1057,13 @@
     }
     
   } else {
-    // zero rate
+    // zero rate - not representable
     
-    switch (r) {
-      case round_up: {
-	break;
-      }
-      case round_down: {
-	return -EINVAL;
-	break;
-      }
-      case round_nearest: {
-	break;
-      }
+    if (r == round_down) {
+      return -EINVAL;
+    } else {
+      exp = 0;
+      man = 0;
     }
     
   }
@@ -1104,18 +1095,17 @@
   struct atm_trafprm * txtp;
   struct atm_trafprm * rxtp;
   u16 tx_rate_bits;
-  u16 tx_vc_bits = 0; /* silence gcc */
-  u16 tx_frame_bits = 0;
-  // int pcr;
+  u16 tx_vc_bits = -1; // hush gcc
+  u16 tx_frame_bits = -1; // hush gcc
   
   amb_dev * dev = AMB_DEV(atm_vcc->dev);
   amb_vcc * vcc;
-  unsigned char pool = -1; // compiler warning
+  unsigned char pool = -1; // hush gcc
   
   PRINTD (DBG_FLOW|DBG_VCC, "amb_open %x %x", vpi, vci);
   
+#ifdef ATM_VPI_UNSPEC
   // UNSPEC is deprecated, remove this code eventually
-#if defined ATM_VPI_UNSPEC
   if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) {
     PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)");
     return -EINVAL;
@@ -1250,25 +1240,23 @@
       // RXer on the channel already, just modify rate...
       cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
       cmd.args.modify_rate.vc = cpu_to_be32 (vci);  // vpi 0
-      // only lower 16 bits used (BE nightmare continues)
-      cmd.args.modify_rate.rate = cpu_to_be16 (tx_rate_bits);
+      cmd.args.modify_rate.rate = cpu_to_be32 (tx_rate_bits << SRB_RATE_SHIFT);
       while (command_do (dev, &cmd))
 	schedule();
       // ... and TX flags, preserving the RX pool
       cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
       cmd.args.modify_flags.vc = cpu_to_be32 (vci);  // vpi 0
-      // only lower 16 bits used (BE nightmare continues)
-      cmd.args.modify_flags.flags = cpu_to_be16
-	((AMB_VCC(dev->rxer[vci])->rx_info.pool << SRB_POOL_SHIFT) | tx_vc_bits);
+      cmd.args.modify_flags.flags = cpu_to_be32
+	( (AMB_VCC(dev->rxer[vci])->rx_info.pool << SRB_POOL_SHIFT)
+	  | (tx_vc_bits << SRB_FLAGS_SHIFT) );
       while (command_do (dev, &cmd))
 	schedule();
     } else {
       // no RXer on the channel, just open (with pool zero)
       cmd.request = cpu_to_be32 (SRB_OPEN_VC);
       cmd.args.open.vc = cpu_to_be32 (vci);  // vpi 0
-      // only lower 16 bits used (BE nightmare continues)
-      cmd.args.open.flags = cpu_to_be16	(tx_vc_bits);
-      cmd.args.open.rate = cpu_to_be16 (tx_rate_bits);
+      cmd.args.open.flags = cpu_to_be32 (tx_vc_bits << SRB_FLAGS_SHIFT);
+      cmd.args.open.rate = cpu_to_be32 (tx_rate_bits << SRB_RATE_SHIFT);
       while (command_do (dev, &cmd))
 	schedule();
     }
@@ -1282,7 +1270,6 @@
     vcc->rx_info.pool = pool;
     
     down (&dev->vcc_sf); 
-    
     /* grow RX buffer pool */
     if (!dev->rxq[pool].buffers_wanted)
       dev->rxq[pool].buffers_wanted = rx_lats;
@@ -1294,16 +1281,15 @@
       // switch (from pool zero) to this pool, preserving the TX bits
       cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
       cmd.args.modify_flags.vc = cpu_to_be32 (vci);  // vpi 0
-      // only lower 16 bits used (BE nightmare continues)
-      cmd.args.modify_flags.flags = cpu_to_be16
-	((pool << SRB_POOL_SHIFT) | dev->txer[vci].tx_vc_bits);
+      cmd.args.modify_flags.flags = cpu_to_be32
+	( (pool << SRB_POOL_SHIFT)
+	  | (dev->txer[vci].tx_vc_bits << SRB_FLAGS_SHIFT) );
     } else {
       // no TXer on the channel, open the VC (with no rate info)
       cmd.request = cpu_to_be32 (SRB_OPEN_VC);
       cmd.args.open.vc = cpu_to_be32 (vci);  // vpi 0
-      // only lower 16 bits used in the next two (BE nightmare continues)
-      cmd.args.open.flags = cpu_to_be16 (pool << SRB_POOL_SHIFT);
-      cmd.args.open.rate = cpu_to_be16 (0);
+      cmd.args.open.flags = cpu_to_be32 (pool << SRB_POOL_SHIFT);
+      cmd.args.open.rate = cpu_to_be32 (0);
     }
     while (command_do (dev, &cmd))
       schedule();
@@ -1344,8 +1330,7 @@
       // RXer still on the channel, just modify rate... XXX not really needed
       cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
       cmd.args.modify_rate.vc = cpu_to_be32 (vci);  // vpi 0
-      // only lower 16 bits used (BE nightmare continues)
-      cmd.args.modify_rate.rate = cpu_to_be16 (0);
+      cmd.args.modify_rate.rate = cpu_to_be32 (0);
       // ... and clear TX rate flags (XXX to stop RM cell output?), preserving RX pool
     } else {
       // no RXer on the channel, close channel
@@ -1370,8 +1355,8 @@
       // TXer still on the channel, just go to pool zero XXX not really needed
       cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
       cmd.args.modify_flags.vc = cpu_to_be32 (vci);  // vpi 0
-      // only lower 16 bits used (BE nightmare continues)
-      cmd.args.modify_flags.flags = cpu_to_be16 (dev->txer[vci].tx_vc_bits);
+      cmd.args.modify_flags.flags = cpu_to_be32
+	(dev->txer[vci].tx_vc_bits << SRB_FLAGS_SHIFT);
     } else {
       // no TXer on the channel, close the VC
       cmd.request = cpu_to_be32 (SRB_CLOSE_VC);
@@ -1392,7 +1377,6 @@
       dev->rxq[pool].buffers_wanted = 0;
       drain_rx_pool (dev, pool);
     }
-
     up (&dev->vcc_sf);
   }
   
@@ -1674,8 +1658,8 @@
   amb_open,
   amb_close,
   NULL,          // no amb_ioctl,
-  NULL, // amb_getsockopt,
-  NULL, // amb_setsockopt,
+  NULL,          // no amb_getsockopt,
+  NULL,          // no amb_setsockopt,
   amb_send,
   amb_sg_send,
   NULL,          // no send_oam    - not in fact used yet
@@ -1718,8 +1702,9 @@
 
 /********** creation of communication queues **********/
 
-static int create_queues (amb_dev * dev, unsigned int cmds, unsigned int txs,
-			  unsigned int * rxs, unsigned int * rx_buffer_sizes) {
+static int __init create_queues (amb_dev * dev, unsigned int cmds,
+				 unsigned int txs, unsigned int * rxs,
+				 unsigned int * rx_buffer_sizes) {
   unsigned char pool;
   size_t total = 0;
   void * memory;
@@ -1848,8 +1833,8 @@
 
 /********** basic loader commands and error handling **********/
 
-static int do_loader_command (const amb_dev * dev, loader_command cmd,
-			      volatile loader_block * lb) {
+static int __init do_loader_command (const amb_dev * dev, loader_command cmd,
+				     volatile loader_block * lb) {
   
   // centisecond timeouts - guessing away here
   unsigned int command_timeouts [] = {
@@ -1865,8 +1850,7 @@
     [adap_run_in_iram]     = 1,
     [adap_end_download]    = 1
   };
-
-#if 0 /* unused */
+  
   unsigned int command_successes [] = {
     [host_memory_test]     = COMMAND_PASSED_TEST,
     [read_adapter_memory]  = COMMAND_READ_DATA_OK,
@@ -1880,11 +1864,14 @@
     [adap_run_in_iram]     = COMMAND_COMPLETE,
     [adap_end_download]    = COMMAND_COMPLETE
   };
-#endif
   
-  int decode_loader_error (u32 result) {
+  int decode_loader_result (loader_command cmd, u32 result) {
     int res;
     const char * msg;
+    
+    if (result == command_successes[cmd])
+      return 0;
+    
     switch (result) {
       case BAD_COMMAND:
 	res = -EINVAL;
@@ -1937,12 +1924,12 @@
       default:
 	res = -EINVAL;
 	msg = "unknown error";
-	PRINTD (DBG_LOAD|DBG_ERR, "decode_loader_error got %d=%x !",
+	PRINTD (DBG_LOAD|DBG_ERR, "decode_loader_result got %d=%x !",
 		result, result);
 	break;
     }
-    if (res)
-      PRINTK (KERN_ERR, "%s", msg);
+    
+    PRINTK (KERN_ERR, "%s", msg);
     return res;
   }
   
@@ -1967,7 +1954,7 @@
   
   timeout = command_timeouts[cmd] * HZ/100;
   
-  while (!lb->result || lb->result == be32_to_cpu (COMMAND_IN_PROGRESS))
+  while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS))
     if (timeout) {
       timeout = schedule_timeout (timeout);
     } else {
@@ -1991,25 +1978,14 @@
       }
     return 0;
   } else {
-    return decode_loader_error (be32_to_cpu (lb->result));
+    return decode_loader_result (cmd, be32_to_cpu (lb->result));
   }
   
-#if 0
-  if ((res != COMMAND_PASSED_TEST) &&
-      (res != COMMAND_READ_DATA_OK) &&
-      (res != COMMAND_WRITE_DATA_OK) &&
-      (res != COMMAND_COMPLETE)) {
-    PRINTD (DBG_LOAD|DBG_ERR"startup cmd %d failed with error %08x",
-	    cmd, res);
-    dump_registers (dev);
-    return -EIO;
-  }
-#endif
 }
 
 /* loader: determine loader version */
 
-static int get_loader_version (const amb_dev * dev, u32 * version) {
+static int __init get_loader_version (const amb_dev * dev, u32 * version) {
   loader_block lb;
   int res;
   
@@ -2025,8 +2001,8 @@
 
 /* loader: read or verify memory data blocks */
 
-static int loader_write (const amb_dev * dev, const u32 * data,
-		  u32 address, unsigned int count) {
+static int __init loader_write (const amb_dev * dev, const u32 * data,
+				u32 address, unsigned int count) {
   unsigned int i;
   loader_block lb;
   transfer_block * tb = &lb.payload.transfer;
@@ -2042,8 +2018,8 @@
   return do_loader_command (dev, write_adapter_memory, &lb);
 }
 
-static int loader_verify (const amb_dev * dev, const u32 * data,
-		   u32 address, unsigned int count) {
+static int __init loader_verify (const amb_dev * dev, const u32 * data,
+				 u32 address, unsigned int count) {
   unsigned int i;
   loader_block lb;
   transfer_block * tb = &lb.payload.transfer;
@@ -2065,7 +2041,7 @@
   return res;
 }
 
-static int loader_start (const amb_dev * dev, u32 address) {
+static int __init loader_start (const amb_dev * dev, u32 address) {
   loader_block lb;
   
   PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");
@@ -2139,7 +2115,7 @@
 
 /********** transfer and start the microcode **********/
 
-static int ucode_init (amb_dev * dev) {
+static int __init ucode_init (amb_dev * dev) {
   unsigned int i = 0;
   unsigned int total = 0;
   const u32 * pointer = ucode_data;
@@ -2185,7 +2161,7 @@
 
 /********** give adapter parameters **********/
 
-static int amb_talk (amb_dev * dev) {
+static int __init amb_talk (amb_dev * dev) {
   adap_talk_block a;
   unsigned char pool;
   unsigned long timeout;
@@ -2238,7 +2214,7 @@
 }
 
 // get microcode version
-static void amb_ucode_version (amb_dev * dev) {
+static void __init amb_ucode_version (amb_dev * dev) {
   u32 major;
   u32 minor;
   command cmd;
@@ -2251,11 +2227,11 @@
 }
 
 // get end station address
-static void amb_esi (amb_dev * dev, u8 * esi) {
+static void __init amb_esi (amb_dev * dev, u8 * esi) {
   u32 lower4;
   u16 upper2;
   command cmd;
-
+  
   // swap bits within byte to get Ethernet ordering
   u8 bit_swap (u8 byte) {
     const u8 swap[] = {
@@ -2266,14 +2242,14 @@
     };
     return ((swap[byte & 0xf]<<4) | swap[byte>>4]);
   }
-
+  
   cmd.request = cpu_to_be32 (SRB_GET_BIA);
   while (command_do (dev, &cmd))
     schedule();
   lower4 = be32_to_cpu (cmd.args.bia.lower4);
   upper2 = be32_to_cpu (cmd.args.bia.upper2);
   PRINTD (DBG_LOAD, "BIA: lower4: %08x, upper2 %04x", lower4, upper2);
-
+  
   if (esi) {
     unsigned int i;
     
@@ -2292,7 +2268,7 @@
   return;
 }
 
-static int amb_init (amb_dev * dev) {
+static int __init amb_init (amb_dev * dev) {
   u32 version;
   
   /* enable adapter doorbell */
@@ -2381,8 +2357,8 @@
 #endif
     
     // semaphore for txer/rxer modifications - we cannot use a
-    // spinlock as the critical region needs to process switches
-    init_MUTEX(&dev->vcc_sf);
+    // spinlock as the critical region needs to switch processes
+    init_MUTEX (&dev->vcc_sf);
     // queue manipulation spinlocks; we want atomic reads and
     // writes to the queue descriptors (handles IRQ and SMP)
     // consider replacing "int pending" -> "atomic_t available"
@@ -2618,8 +2594,6 @@
 
 int __init amb_detect (void) {
   int devs;
-  
-  PRINTD (DBG_FLOW|DBG_INIT, "init_module");
   
   // sanity check - cast needed as printk does not support %Zu
   if (sizeof(amb_mem) != 4*16 + 4*12) {
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/ambassador.h linux/drivers/atm/ambassador.h
--- v2.3.17/linux/drivers/atm/ambassador.h	Thu Aug 26 13:05:34 1999
+++ linux/drivers/atm/ambassador.h	Wed Sep  8 11:14:31 1999
@@ -20,11 +20,6 @@
   system and in the file COPYING in the Linux kernel source.
 */
 
-/*
-  IMPORTANT NOTE: Madge Networks does not license the microcode for
-  this driver under the GPL. See the .data file for the licence.
-*/
-
 #ifndef AMBASSADOR_H
 #define AMBASSADOR_H
 
@@ -117,9 +112,6 @@
 // minimum RX buffers required to cope with replenishing delay
 #define MIN_RX_BUFFERS	   1
 
-// RX buffer tailroom to cope with writing too much
-#define RX_FUDGE           3
-
 // minimum PCI latency we will tolerate (32 IS TOO SMALL)
 #define MIN_PCI_LATENCY   64 // 255
 
@@ -217,7 +209,9 @@
 /* RxPool2:	0x0040		*/
 /* RxPool3:	0x0060		*/
 
-#define SRB_POOL_SHIFT           5
+#define SRB_RATE_SHIFT          16
+#define SRB_POOL_SHIFT          (SRB_FLAGS_SHIFT+5)
+#define SRB_FLAGS_SHIFT         16
 
 #define	SRB_STOP_TASKING	19
 #define	SRB_START_TASKING	20
@@ -339,8 +333,6 @@
   u32 reset_control;
 } amb_mem;
 
-#define mem ((amb_mem *)0)
-
 /* IRQ (card to host) and doorbell (host to card) enable bits */
 #define AMB_INTERRUPT_BITS 0x00030000
 #define AMB_DOORBELL_BITS  0x00000300
@@ -435,12 +427,10 @@
 
 typedef struct {
   u32	handle;
-  // really? what about a BE host?
   u16	vc;
   u16	next_descriptor_length;
   u32	next_descriptor;
 #ifdef AMB_NEW_MICROCODE
-  // BE host?
   u8    cpcs_uu;
   u8    cpi;
   u16   pad;
@@ -463,7 +453,6 @@
 /* this "points" to the sequence of fragments and trailer */
 
 typedef	struct {
-  // what about a BE host?
   u16	vc;
   u16	tx_descr_length;
   u32	tx_descr_addr;
@@ -483,7 +472,6 @@
 
 typedef struct {
   u32  handle;
-  // what about a BE host?
   u16  vc;
   u16  lec_id; // unused
   u16  status;
@@ -526,7 +514,6 @@
     u32 buffer_size;		/* size of host buffer */
   } rec_struct[NUM_RX_POOLS];
 #ifdef AMB_NEW_MICROCODE
-  // BE?
   u16 init_flags;
   u16 talk_block_spare;
 #endif
@@ -538,7 +525,6 @@
    GET_SUNI_STATS */
 
 typedef struct {
-  // what about a BE host?
   u8	racp_chcs;
   u8	racp_uhcs;
   u16	spare;
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/atmtcp.c linux/drivers/atm/atmtcp.c
--- v2.3.17/linux/drivers/atm/atmtcp.c	Thu Aug 26 13:05:34 1999
+++ linux/drivers/atm/atmtcp.c	Wed Sep  8 11:14:31 1999
@@ -1,13 +1,13 @@
 /* drivers/atm/atmtcp.c - ATM over TCP "device" driver */
 
-/* Written 1997,1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1997-1999 by Werner Almesberger, EPFL LRC/ICA */
 
 
 #include <linux/module.h>
+#include <linux/wait.h>
 #include <linux/atmdev.h>
 #include <linux/atm_tcp.h>
 #include <asm/uaccess.h>
-#include "../../net/atm/tunable.h" /* @@@ fix this */
 #include "../../net/atm/protocols.h" /* @@@ fix this */
 
 
@@ -26,6 +26,75 @@
 #define MAX_VCI_BITS 16
 
 
+/*
+ * Hairy code ahead: the control VCC may be closed while we're still
+ * waiting for an answer, so we need to re-validate out_vcc every once
+ * in a while.
+ */
+
+
+static int atmtcp_send_control(struct atm_vcc *vcc,int type,
+    const struct atmtcp_control *msg,unsigned short flag)
+{
+	struct atm_vcc *out_vcc;
+	struct sk_buff *skb;
+	struct atmtcp_control *new_msg;
+	unsigned short old_flags;
+
+	out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
+	if (!out_vcc) return -EUNATCH;
+	skb = alloc_skb(sizeof(*msg),GFP_KERNEL);
+	if (!skb) return -ENOMEM;
+	mb();
+	out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
+	if (!out_vcc) {
+		dev_kfree_skb(skb);
+		return -EUNATCH;
+	}
+	atm_force_charge(out_vcc,skb->truesize);
+	new_msg = (struct atmtcp_control *) skb_put(skb,sizeof(*new_msg));
+	*new_msg = *msg;
+	new_msg->hdr.length = ATMTCP_HDR_MAGIC;
+	new_msg->type = type;
+	new_msg->vcc = (unsigned long) vcc;
+	old_flags = vcc->flags;
+	out_vcc->push(out_vcc,skb);
+	while (!((vcc->flags ^ old_flags) & flag)) {
+		mb();
+		out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
+		if (!out_vcc) return -EUNATCH;
+		sleep_on(&vcc->sleep);
+		
+	}
+	return 0;
+}
+
+
+static int atmtcp_recv_control(const struct atmtcp_control *msg)
+{
+	struct atm_vcc *vcc = (struct atm_vcc *) msg->vcc;
+
+	vcc->vpi = msg->addr.sap_addr.vpi;
+	vcc->vci = msg->addr.sap_addr.vci;
+	vcc->qos = msg->qos;
+	vcc->reply = msg->result;
+	switch (msg->type) {
+	    case ATMTCP_CTRL_OPEN:
+		vcc->flags ^= ATM_VF_READY;
+		break;
+	    case ATMTCP_CTRL_CLOSE:
+		vcc->flags ^= ATM_VF_ADDR;
+		break;
+	    default:
+		printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n",
+		    msg->type);
+		return -EINVAL;
+	}
+	wake_up(&vcc->sleep);
+	return 0;
+}
+
+
 static void atmtcp_v_dev_close(struct atm_dev *dev)
 {
 	MOD_DEC_USE_COUNT;
@@ -34,21 +103,38 @@
 
 static int atmtcp_v_open(struct atm_vcc *vcc,short vpi,int vci)
 {
+	struct atmtcp_control msg;
 	int error;
 
-	error = atm_find_ci(vcc,&vpi,&vci);
+	memset(&msg,0,sizeof(msg));
+	msg.addr.sap_family = AF_ATMPVC;
+	msg.hdr.vpi = htons(vpi);
+	msg.addr.sap_addr.vpi = vpi;
+	msg.hdr.vci = htons(vci);
+	msg.addr.sap_addr.vci = vci;
+	error = atm_find_ci(vcc,&msg.addr.sap_addr.vpi,&msg.addr.sap_addr.vci);
 	if (error) return error;
-	vcc->vpi = vpi;
-	vcc->vci = vci;
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0;
-	vcc->flags |= ATM_VF_ADDR | ATM_VF_READY;
-	return 0;
+	msg.type = ATMTCP_CTRL_OPEN;
+	msg.qos = vcc->qos;
+	vcc->flags |= ATM_VF_ADDR;
+	vcc->flags &= ~ATM_VF_READY; /* just in case ... */
+	error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY);
+	if (error) return error;
+	return vcc->reply;
 }
 
 
 static void atmtcp_v_close(struct atm_vcc *vcc)
 {
-	vcc->flags &= ~(ATM_VF_READY | ATM_VF_ADDR);
+	struct atmtcp_control msg;
+
+	memset(&msg,0,sizeof(msg));
+	msg.addr.sap_family = AF_ATMPVC;
+	msg.addr.sap_addr.vpi = vcc->vpi;
+	msg.addr.sap_addr.vci = vcc->vci;
+	vcc->flags &= ~ATM_VF_READY;
+	(void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR);
 }
 
 
@@ -89,12 +175,7 @@
 		return -ENOLINK;
 	}
 	size = skb->len+sizeof(struct atmtcp_hdr);
-	if (!atm_charge(out_vcc,atm_pdu2truesize(size))) new_skb = NULL;
-	else {
-		new_skb = alloc_skb(size,GFP_ATOMIC);
-		if (!new_skb)
-			atm_return(out_vcc,atm_pdu2truesize(size));
-	}
+	new_skb = atm_alloc_charge(out_vcc,size,GFP_ATOMIC);
 	if (!new_skb) {
 		if (vcc->pop) vcc->pop(vcc,skb);
 		else dev_kfree_skb(skb);
@@ -128,14 +209,18 @@
 {
 	struct atm_dev *atmtcp_dev;
 	struct atmtcp_dev_data *dev_data;
+	struct atm_vcc *walk;
 
 	atmtcp_dev = (struct atm_dev *) vcc->dev_data;
 	dev_data = PRIV(atmtcp_dev);
 	dev_data->vcc = NULL;
 	if (dev_data->persist) return;
+	PRIV(atmtcp_dev) = NULL;
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
+	for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
+		wake_up(&walk->sleep);
 }
 
 
@@ -145,37 +230,38 @@
 	struct atmtcp_hdr *hdr;
 	struct atm_vcc *out_vcc;
 	struct sk_buff *new_skb;
+	int result = 0;
 
 	if (!skb->len) return 0;
 	dev = vcc->dev_data;
-	hdr = (void *) skb->data;
+	hdr = (struct atmtcp_hdr *) skb->data;
+	if (hdr->length == ATMTCP_HDR_MAGIC) {
+		result = atmtcp_recv_control(
+		    (struct atmtcp_control *) skb->data);
+		goto done;
+	}
 	for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
 		if (out_vcc->vpi == ntohs(hdr->vpi) &&
 		    out_vcc->vci == ntohs(hdr->vci) &&
 		    out_vcc->qos.rxtp.traffic_class != ATM_NONE)
 			break;
 	if (!out_vcc) {
-		if (vcc->pop) vcc->pop(vcc,skb);
-		else dev_kfree_skb(skb);
 		vcc->stats->tx_err++;
-		return 0;
+		goto done;
 	}
 	skb_pull(skb,sizeof(struct atmtcp_hdr));
-	if (!atm_charge(out_vcc,atm_pdu2truesize(skb->len))) new_skb = NULL;
-	else {
-		new_skb = alloc_skb(skb->len,GFP_KERNEL);
-		if (!new_skb) atm_return(out_vcc,atm_pdu2truesize(skb->len));
-        }
+	new_skb = atm_alloc_charge(out_vcc,skb->len,GFP_KERNEL);
 	if (!new_skb) {
-		if (vcc->pop) vcc->pop(vcc,skb);
-		else dev_kfree_skb(skb);
-	 	return -ENOBUFS;
+		result = -ENOBUFS;
+		goto done;
 	}
+	new_skb->stamp = xtime;
 	memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
+	out_vcc->push(out_vcc,new_skb);
+done:
 	if (vcc->pop) vcc->pop(vcc,skb);
 	else dev_kfree_skb(skb);
-	out_vcc->push(out_vcc,new_skb);
-	return 0;
+	return result;
 }
 
 
@@ -323,8 +409,12 @@
 	return 0;
 }
 
+
 void cleanup_module(void)
 {
+	atm_tcp_ops.attach = NULL;
+	atm_tcp_ops.create_persistent = NULL;
+	atm_tcp_ops.remove_persistent = NULL;
 }
 
 #else
@@ -336,4 +426,3 @@
 };
 
 #endif
-    
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/eni.c linux/drivers/atm/eni.c
--- v2.3.17/linux/drivers/atm/eni.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/atm/eni.c	Wed Sep  8 11:14:31 1999
@@ -522,11 +522,7 @@
 	else {
 		length = ATM_CELL_SIZE-1; /* no HEC */
 	}
-	if (!length || !atm_charge(vcc,atm_pdu2truesize(length))) skb = NULL;
-	else {
-		skb = alloc_skb(length,GFP_ATOMIC);
-		if (!skb) atm_return(vcc,atm_pdu2truesize(length));
-	}
+	skb = length ? atm_alloc_charge(vcc,length,GFP_ATOMIC) : NULL;
 	if (!skb) {
 		discard(vcc,length >> 2);
 		return 0;
@@ -596,16 +592,7 @@
 			vcc->stats->rx_err++;
 		}
 	}
-	if (!eff || !atm_charge(vcc,atm_pdu2truesize(eff << 2))) skb = NULL;
-	else {
-		skb = alloc_skb(eff << 2,GFP_ATOMIC);
-		if (!skb) {
-			EVENT("peek reject (eff << 2=%ld)\n",eff << 2,0);
-			DPRINTK(DEV_LABEL "(itf %d): peek reject for %ld "
-			    "bytes\n",vcc->dev->number,eff << 2);
-			atm_return(vcc,atm_pdu2truesize(eff << 2));
-		}
-	}
+	skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL;
 	if (!skb) {
 		discard(vcc,size);
 		return 0;
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/horizon.c linux/drivers/atm/horizon.c
--- v2.3.17/linux/drivers/atm/horizon.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/atm/horizon.c	Wed Sep  8 11:14:31 1999
@@ -50,9 +50,9 @@
 
 #define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>"
 #define description_string "Madge ATM Horizon [Ultra] driver"
-#define version_string "1.1"
+#define version_string "1.2"
 
-static void __init show_version (void) {
+static inline void __init show_version (void) {
   printk ("%s version %s\n", description_string, version_string);
 }
 
@@ -86,7 +86,7 @@
   
   The driver is only known to work with SONET and UTP Horizon Ultra
   cards at 155Mb/s. However, code is in place to deal with both the
-  original Horizon and 35Mb/s.
+  original Horizon and 25Mb/s operation.
   
   There are two revisions of the Horizon ASIC: the original and the
   Ultra. Details of hardware bugs are in section III.
@@ -127,15 +127,15 @@
   
   3. Initialisation
   
-  The card is reset and then put into a know state. The physical layer
-  is configured for normal operation at the appropriate speed; in the
-  case of the 155 cards, the framer is initialised with line-based
-  timing; the internal RAM is zeroed and the allocation of buffers for
-  RX and TX is made; the Burnt In Address is read and copied to the
-  ATM ESI; various policy settings for RX (VPI bits, unknown VCs, oam
-  cells) are made. Ideally all policy items should be configurable at
-  module load (if not actually on-demand), however, only the vpi vs
-  vci bit allocation can be specified at insmod.
+  The card is reset and then put into a known state. The physical
+  layer is configured for normal operation at the appropriate speed;
+  in the case of the 155 cards, the framer is initialised with
+  line-based timing; the internal RAM is zeroed and the allocation of
+  buffers for RX and TX is made; the Burnt In Address is read and
+  copied to the ATM ESI; various policy settings for RX (VPI bits,
+  unknown VCs, oam cells) are made. Ideally all policy items should be
+  configurable at module load (if not actually on-demand), however,
+  only the vpi vs vci bit allocation can be specified at insmod.
   
   4. Shutdown
   
@@ -152,12 +152,12 @@
   the following items they make up the traffic specification.
   
   struct atm_trafprm {
-  unsigned char  traffic_class; traffic class (ATM_UBR, ...)
-  int		   max_pcr;	  maximum PCR in cells per second
-  int		   pcr;		  desired PCR in cells per second
-  int		   min_pcr;	  minimum PCR in cells per second
-  int	           max_cdv;	  maximum CDV in microseconds
-  int              max_sdu;	  maximum SDU in bytes
+    unsigned char traffic_class; traffic class (ATM_UBR, ...)
+    int           max_pcr;       maximum PCR in cells per second
+    int           pcr;           desired PCR in cells per second
+    int           min_pcr;       minimum PCR in cells per second
+    int           max_cdv;       maximum CDV in microseconds
+    int           max_sdu;       maximum SDU in bytes
   };
   
   Note that these denote bandwidth available not bandwidth used; the
@@ -206,30 +206,31 @@
   
   AAL types are:
   
-  ATM_NO_AAL	AAL not specified
-  ATM_AAL0	"raw" ATM cells
-  ATM_AAL1	AAL1 (CBR)
-  ATM_AAL2	AAL2 (VBR)
-  ATM_AAL34	AAL3/4 (data)
-  ATM_AAL5	AAL5 (data)
-  ATM_SAAL	signaling AAL
+  ATM_NO_AAL    AAL not specified
+  ATM_AAL0      "raw" ATM cells
+  ATM_AAL1      AAL1 (CBR)
+  ATM_AAL2      AAL2 (VBR)
+  ATM_AAL34     AAL3/4 (data)
+  ATM_AAL5      AAL5 (data)
+  ATM_SAAL      signaling AAL
   
   The Horizon has support for AAL frame types: 0, 3/4 and 5. However,
   it does not implement AAL 3/4 SAR and it has a different notion of
   "raw cell" to ATM Linux's (48 bytes vs. 52 bytes) so neither are
   supported by this driver.
   
-  The Horizon has (TX) support for ABR (including UBR), VBR and CBR.
-  Each TX channel has a bucket (containing up to 31 cell units) and
-  two timers (PCR and SCR) associated with it that can be used to
-  govern cell emissions and host notification (in the case of
-  ABR). The timers may either be disabled or may be set to any of 240
-  values (determined by the clock crystal, a fixed (?) per-device
-  divider, a configurable divider and a configurable timer preload
-  value).
-  
-  At the moment only UBR and CBR are supported by the driver. This is
-  due to my not understanding ATM Linux VBR or Horizon's VBR support.
+  The Horizon has limited support for ABR (including UBR), VBR and
+  CBR. Each TX channel has a bucket (containing up to 31 cell units)
+  and two timers (PCR and SCR) associated with it that can be used to
+  govern cell emissions and host notification (in the case of ABR this
+  is presumably so that RM cells may be emitted at appropriate times).
+  The timers may either be disabled or may be set to any of 240 values
+  (determined by the clock crystal, a fixed (?) per-device divider, a
+  configurable divider and a configurable timer preload value).
+  
+  At the moment only UBR and CBR are supported by the driver. VBR will
+  be supported as soon as ATM for Linux supports it. ABR support is
+  very unlikely as RM cell handling is completely up to the driver.
   
   1. TX (TX channel setup and TX transfer)
   
@@ -305,7 +306,7 @@
   in the TX direction on the original Horizon. More complicated
   solutions are likely to hurt my brain.
   
-  3. Loss of buffer on close VC
+  2. Loss of buffer on close VC
   
   When a VC is being closed, the buffer associated with it is not
   returned to the pool. The host must store the reference to this
@@ -314,7 +315,7 @@
   The host intervention currently consists of stacking such a buffer
   pointer at VC close and checking the stack at VC open.
   
-  4. Failure to close a VC
+  3. Failure to close a VC
   
   If a VC is currently receiving a frame then closing the VC may fail
   and the frame continues to be received.
@@ -322,7 +323,7 @@
   The solution is to make sure any received frames are flushed when
   ready. This is currently done just before the solution to 3.
   
-  5. PCI bus (original Horizon only, fixed in Ultra)
+  4. PCI bus (original Horizon only, fixed in Ultra)
   
   Reading from the data port prior to initialisation will hang the PCI
   bus. Just don't do that then! We don't.
@@ -388,10 +389,9 @@
   insb (dev->iobase + reg, addr, len);
 }
 
-/* Read / Write to a given address in Horizon buffer memory.                */
-// Interrupts must be disabled between the address register and data port
-// accesses as these must form an atomic operation.
-
+/* Read / Write to a given address in Horizon buffer memory.
+   Interrupts must be disabled between the address register and data
+   port accesses as these must form an atomic operation. */
 static inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) {
   // wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr);
   wr_regl (dev, MEM_WR_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW));
@@ -401,7 +401,7 @@
 static inline u32 rd_mem (const hrz_dev * dev, HDW * addr) {
   // wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr);
   wr_regl (dev, MEM_RD_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW));
-  return rd_regl(dev, MEMORY_PORT_OFF);
+  return rd_regl (dev, MEMORY_PORT_OFF);
 }
 
 static inline void wr_framer (const hrz_dev * dev, u32 addr, u32 data) {
@@ -511,7 +511,7 @@
 
 /* RX channels are 10 bit integers, these fns are quite paranoid */
 
-static inline int channel_to_vpci (const u16 channel, short * vpi, int * vci) {
+static inline int channel_to_vpivci (const u16 channel, short * vpi, int * vci) {
   unsigned short vci_bits = 10 - vpi_bits;
   if ((channel & RX_CHANNEL_MASK) == channel) {
     *vci = channel & ((~0)<<vci_bits);
@@ -521,7 +521,7 @@
   return -EINVAL;
 }
 
-static inline int vpci_to_channel (u16 * channel, const short vpi, const int vci) {
+static inline int vpivci_to_channel (u16 * channel, const short vpi, const int vci) {
   unsigned short vci_bits = 10 - vpi_bits;
   if (0 <= vpi && vpi < 1<<vpi_bits && 0 <= vci && vci < 1<<vci_bits) {
     *channel = vpi<<vci_bits | vci;
@@ -746,7 +746,7 @@
 static int hrz_open_rx (hrz_dev * dev, u16 channel) {
   // is there any guarantee that we don't get two simulataneous
   // identical calls of this function from different processes? yes
-  // rates_lock
+  // rate_lock
   unsigned long flags;
   u32 channel_type; // u16?
   
@@ -786,13 +786,13 @@
   spin_lock_irqsave (&dev->mem_lock, flags);
   
   wr_mem (dev, &rx_desc->wr_buf_type,
-          buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME);
+	  buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME);
   if (buf_ptr != RX_CHANNEL_IDLE)
     wr_mem (dev, &rx_desc->rd_buf_type, buf_ptr);
   
   spin_unlock_irqrestore (&dev->mem_lock, flags);
   
-  //    rxer->rate = make_rate (qos->peak_cells);
+  // rxer->rate = make_rate (qos->peak_cells);
   
   PRINTD (DBG_FLOW, "hrz_open_rx ok");
   
@@ -1340,12 +1340,12 @@
       if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) {
 	
 	if (rx_len <= atm_vcc->qos.rxtp.max_sdu) {
-	  
+	  struct sk_buff *skb = atm_alloc_charge(atm_vcc,rx_len,GFP_ATOMIC);
+
 	  // If everyone has to call atm_pdu2... why isn't it part of
 	  // atm_charge? B'cos some people already have skb->truesize!
-	  if (atm_charge (atm_vcc, atm_pdu2truesize (rx_len))) {
-	    
-	    struct sk_buff * skb = alloc_skb (rx_len, GFP_ATOMIC);
+	  // WA: well. even if they think they do, they might not ... :-)
+
 	    if (skb) {
 	      // remember this so we can push it later
 	      dev->rx_skb = skb;
@@ -1369,15 +1369,8 @@
 	      return;
 	      
 	    } else {
-	      PRINTD (DBG_SKB|DBG_WARN, "failed to get skb");
-	      atm_vcc->stats->rx_drop++;
+	      PRINTD (DBG_INFO, "failed to get skb");
 	    }
-	    
-	  } else {
-	    // someone fix this (message), please!
-	    PRINTD (DBG_INFO, "dropped thanks to atm_charge");
-	    // drop stats incremented in atm_charge
-	  }
 	  
 	} else {
 	  PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel);
@@ -1385,7 +1378,7 @@
 	}
 	
       } else {
-      	PRINTK (KERN_WARNING, "dropped over-size frame");
+	PRINTK (KERN_WARNING, "dropped over-size frame");
 	// do we count this?
       }
       
@@ -1573,7 +1566,7 @@
 			      vcc->tx_pcr_bits);
 
 #if 0
-    if (a vbr channel) {
+    if (vcc->tx_xbr_bits == VBR_RATE_TYPE) {
       // SCR timer
       update_tx_channel_config (dev, tx_channel, SCR_TIMER_ACCESS,
 				vcc->tx_scr_bits);
@@ -1584,9 +1577,9 @@
       
       // ... and fullness
       update_tx_channel_config (dev, tx_channel, BUCKET_FULLNESS_ACCESS,
-			      vcc->tx_bucket_bits);
+				vcc->tx_bucket_bits);
     }
-#endif    
+#endif
 
     // Initialise the read and write buffer pointers
     rd_ptr = rd_mem (dev, &tx_desc->rd_buf_type) & BUFFER_PTR_MASK;
@@ -1723,7 +1716,7 @@
 	    free_buffers, buffers_required);
     // what is the appropriate delay? implement a timeout? (depending on line speed?)
     // mdelay (1);
-    // what happens if  kill (current_pid, SIGKILL) ?
+    // what happens if we kill (current_pid, SIGKILL) ?
     schedule();
     if (++spin_count > 1000) {
       PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d",
@@ -1743,7 +1736,7 @@
     for (tx_channel = 0; tx_channel < TX_CHANS; ++tx_channel)
       if (dev->tx_channel_record[tx_channel] == channel) {
 	PRINTD (DBG_TX, "vc already on channel: hit");
-        break;
+	break;
       }
     if (tx_channel == TX_CHANS) { 
       PRINTD (DBG_TX, "vc already on channel: miss");
@@ -1802,7 +1795,7 @@
 
 /********** reset a card **********/
 
-static void __init hrz_reset_card (const hrz_dev * dev) {
+static void __init hrz_reset (const hrz_dev * dev) {
   u32 control_0_reg = rd_regl (dev, CONTROL_0_REG);
   
   // why not set RESET_HORIZON to one and wait for the card to
@@ -1813,7 +1806,7 @@
     control_0_reg = rd_regl (dev, CONTROL_0_REG);
   
   // old reset code retained:
-  wr_regl (dev,  CONTROL_0_REG, control_0_reg |
+  wr_regl (dev, CONTROL_0_REG, control_0_reg |
 	   RESET_ATM | RESET_RX | RESET_TX | RESET_HOST);
   // just guessing here
   udelay (1000);
@@ -1821,18 +1814,6 @@
   wr_regl (dev, CONTROL_0_REG, control_0_reg);
 }
 
-/********** shutdown a card **********/
-
-#ifdef MODULE
-
-static void hrz_shutdown (const hrz_dev * dev) {
-  hrz_reset_card (dev);
-  
-  GREEN_LED_OFF(dev);
-}
-
-#endif
-
 /********** read the burnt in address **********/
 
 static u16 __init read_bia (const hrz_dev * dev, u16 addr) {
@@ -1931,7 +1912,7 @@
   // Reset the card to get everything in a known state
   
   printk (" reset");
-  hrz_reset_card (dev);
+  hrz_reset (dev);
   
   // Clear all the buffer memory
   
@@ -2105,9 +2086,9 @@
     
     for (i=0; i < ESI_LEN; ++i) {
       if (i % 2 == 0)
-        b = read_bia (dev, i/2 + 2);
+	b = read_bia (dev, i/2 + 2);
       else
-        b = b >> 8;
+	b = b >> 8;
       esi[i] = b & 0xFF;
       printk ("%02x", esi[i]);
     }
@@ -2199,8 +2180,8 @@
   hrz_vcc * vccp; // allocated late
   PRINTD (DBG_FLOW|DBG_VCC, "hrz_open %x %x", vpi, vci);
   
+#ifdef ATM_VPI_UNSPEC
   // UNSPEC is deprecated, remove this code eventually
-#if defined ATM_VPI_UNSPEC
   if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) {
     PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)");
     return -EINVAL;
@@ -2215,7 +2196,7 @@
   }
   PRINTD (DBG_VCC, "atm_find_ci gives %x %x", vpi, vci);
   
-  error = vpci_to_channel (&channel, vpi, vci);
+  error = vpivci_to_channel (&channel, vpi, vci);
   if (error) {
     PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci);
     return error;
@@ -2459,7 +2440,7 @@
 	  // slight race (no locking) here so we may get -EAGAIN
 	  // later; the greedy bastards would deserve it :)
 	  PRINTD (DBG_QOS, "snatching all remaining RX bandwidth");
-	  pcr = dev->tx_avail;
+	  pcr = dev->rx_avail;
 	} else if (pcr < 0) {
 	  pcr = -pcr;
 	}
@@ -2472,14 +2453,15 @@
 	}
 	break;
       }
+#if 0
       case ATM_VBR: {
-	// int scr = atm_scr_goal (txtp);
+	// int scr = atm_scr_goal (rxtp);
 	int scr = 1<<16; // just for fun
 	if (!scr) {
 	  // slight race (no locking) here so we may get -EAGAIN
 	  // later; the greedy bastards would deserve it :)
 	  PRINTD (DBG_QOS, "snatching all remaining RX bandwidth");
-	  scr = dev->tx_avail;
+	  scr = dev->rx_avail;
 	} else if (scr < 0) {
 	  scr = -scr;
 	}
@@ -2492,6 +2474,7 @@
 	}
 	break;
       }
+#endif
       default: {
 	PRINTD (DBG_QOS, "unsupported RX traffic class");
 	return -EINVAL;
@@ -2632,8 +2615,10 @@
   MOD_DEC_USE_COUNT;
 }
 
+#if 0
 static int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname,
 			   void *optval, int optlen) {
+  hrz_dev * dev = HRZ_DEV(atm_vcc->dev);
   PRINTD (DBG_FLOW|DBG_VCC, "hrz_getsockopt");
   switch (level) {
     case SOL_SOCKET:
@@ -2655,6 +2640,7 @@
 
 static int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname,
 			   void *optval, int optlen) {
+  hrz_dev * dev = HRZ_DEV(atm_vcc->dev);
   PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt");
   switch (level) {
     case SOL_SOCKET:
@@ -2673,6 +2659,7 @@
   }
   return -EINVAL;
 }
+#endif
 
 static int hrz_sg_send (struct atm_vcc * atm_vcc,
 			unsigned long start,
@@ -2722,15 +2709,15 @@
   /* more diagnostics here? */
   
 #if 0
-  {
-    // VBR temporary diags
+  if (!left--) {
+    unsigned int count = sprintf (page, "vbr buckets:");
     unsigned int i;
-    for (i = 0; i < TX_CHANS; ++i) {
-      if (!left--)
-	return sprintf (page, "bucket %u: %u/%u\n", i, 
+    for (i = 0; i < TX_CHANS; ++i)
+      count += sprintf (page, " %u/%u",
 			query_tx_channel_config (dev, i, BUCKET_FULLNESS_ACCESS),
 			query_tx_channel_config (dev, i, BUCKET_CAPACITY_ACCESS));
-    }
+    count += sprintf (page+count, ".\n");
+    return count;
   }
 #endif
   
@@ -2760,8 +2747,8 @@
   hrz_open,
   hrz_close,
   NULL,          // no hrz_ioctl
-  hrz_getsockopt,
-  hrz_setsockopt,
+  NULL,          // hrz_getsockopt,
+  NULL,          // hrz_setsockopt,
   hrz_send,
   hrz_sg_send,
   NULL,          // no send_oam    - not in fact used yet
@@ -2811,10 +2798,10 @@
     
     // grab IRQ and install handler - move this someplace more sensible
     if (request_irq (irq,
-                     interrupt_handler,
-                     SA_SHIRQ, /* irqflags guess */
-                     DEV_LABEL, /* name guess */
-                     dev)) {
+		     interrupt_handler,
+		     SA_SHIRQ, /* irqflags guess */
+		     DEV_LABEL, /* name guess */
+		     dev)) {
       PRINTD (DBG_WARN, "request IRQ failed!");
       // free_irq is at "endif"
     } else {
@@ -2824,20 +2811,20 @@
       
       dev->atm_dev = atm_dev_register (DEV_LABEL, &hrz_ops, -1, 0);
       if (!(dev->atm_dev)) {
-        PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
+	PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
       } else {
 	unsigned char lat;
 	
-        PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
+	PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
 		dev->atm_dev->number, dev, dev->atm_dev);
-        dev->atm_dev->dev_data = (void *) dev;
-        dev->pci_dev = pci_dev; 
-        
-        /* XXX DEV_LABEL is a guess */
-        request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL);
+	dev->atm_dev->dev_data = (void *) dev;
+	dev->pci_dev = pci_dev; 
+	
+	/* XXX DEV_LABEL is a guess */
+	request_region (iobase, HRZ_IO_EXTENT, DEV_LABEL);
 	
-        // enable bus master accesses
-        pci_set_master (pci_dev);
+	// enable bus master accesses
+	pci_set_master (pci_dev);
 	
 	// frobnicate latency (upwards, usually)
 	pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
@@ -2851,9 +2838,9 @@
 	  pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY);
 	}
 	
-        dev->iobase = iobase;
-        dev->irq = irq; 
-        dev->membase = membase; 
+	dev->iobase = iobase;
+	dev->irq = irq; 
+	dev->membase = membase; 
 	
 	dev->rx_q_entry = dev->rx_q_reset = &memmap->rx_q_entries[0];
 	dev->rx_q_wrap  = &memmap->rx_q_entries[RX_CHANS-1];
@@ -2882,13 +2869,13 @@
 	}
 	
 	dev->flags = 0;
-        
+	
 	// Allocate cell rates and remember ASIC version
 	// Fibre: ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53
 	// Copper: (WRONG) we want 6 into the above, close to 25Mb/s
 	// Copper: (plagarise!) 25600000/8/270*260/53 - n/53
 	
-        if (hrz_init (dev)) {
+	if (hrz_init (dev)) {
 	  // to be really pedantic, this should be ATM_OC3c_PCR
 	  dev->tx_avail = ATM_OC3_PCR;
 	  dev->rx_avail = ATM_OC3_PCR;
@@ -2906,21 +2893,25 @@
 	// writes to adapter memory (handles IRQ and SMP)
 	spin_lock_init (&dev->mem_lock);
 	
-	init_waitqueue_head(&dev->tx_queue);
-        
-        // vpi in 0..4, vci in 6..10
-        dev->atm_dev->ci_range.vpi_bits = vpi_bits;
-        dev->atm_dev->ci_range.vci_bits = 10-vpi_bits;
-        
-        // update count and linked list
+#if LINUX_VERSION_CODE >= 0x20303
+	init_waitqueue_head (&dev->tx_queue);
+#else
+	dev->tx_queue = 0;
+#endif
+	
+	// vpi in 0..4, vci in 6..10
+	dev->atm_dev->ci_range.vpi_bits = vpi_bits;
+	dev->atm_dev->ci_range.vci_bits = 10-vpi_bits;
+	
+	// update count and linked list
 	++devs;
-        dev->prev = hrz_devs;
-        hrz_devs = dev;
+	dev->prev = hrz_devs;
+	hrz_devs = dev;
 	// success
-        continue;
-        
-        /* not currently reached */
-        atm_dev_deregister (dev->atm_dev);
+	continue;
+	
+	/* not currently reached */
+	atm_dev_deregister (dev->atm_dev);
       } /* atm_dev_register */
       free_irq (irq, dev);
     } /* request_irq */
@@ -2943,11 +2934,11 @@
   
   if (max_tx_size > TX_AAL5_LIMIT)
     PRINTK (KERN_NOTICE, "max_tx_size has been limited to %hu",
-            max_tx_size = TX_AAL5_LIMIT);
+	    max_tx_size = TX_AAL5_LIMIT);
   
   if (max_rx_size > RX_AAL5_LIMIT)
     PRINTK (KERN_NOTICE, "max_rx_size has been limited to %hu",
-            max_rx_size = RX_AAL5_LIMIT);
+	    max_rx_size = RX_AAL5_LIMIT);
   
   return;
 }
@@ -3016,7 +3007,7 @@
     hrz_devs = dev->prev;
     
     PRINTD (DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
-    hrz_shutdown (dev);
+    hrz_reset (dev);
     atm_dev_deregister (dev->atm_dev);
     free_irq (dev->irq, dev);
     release_region (dev->iobase, HRZ_IO_EXTENT);
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/horizon.h linux/drivers/atm/horizon.h
--- v2.3.17/linux/drivers/atm/horizon.h	Thu Aug 26 13:05:34 1999
+++ linux/drivers/atm/horizon.h	Wed Sep  8 11:14:31 1999
@@ -32,6 +32,9 @@
 
 #include <linux/config.h>
 
+#include <linux/version.h>
+
+
 #ifdef CONFIG_ATM_HORIZON_DEBUG
 #define DEBUG_HORIZON
 #endif
@@ -41,7 +44,7 @@
 #ifndef PCI_VENDOR_ID_MADGE
 #define PCI_VENDOR_ID_MADGE               0x10B6
 #endif
-#ifndef PCI_VENDOR_ID_MADGE_HORIZON
+#ifndef PCI_DEVICE_ID_MADGE_HORIZON
 #define PCI_DEVICE_ID_MADGE_HORIZON       0x1000
 #endif
 
@@ -375,8 +378,6 @@
 
 #define memmap ((MEMMAP *)0)
 
-#define BUF_PTR(cbptr) ((cbptr) - (cell_buf *) 0)
-
 /* end horizon specific bits */
 
 typedef enum {
@@ -423,7 +424,11 @@
   unsigned int        tx_regions; // number of remaining regions
 
   spinlock_t          mem_lock;
+#if LINUX_VERSION_CODE >= 0x20303
   wait_queue_head_t   tx_queue;
+#else
+  struct wait_queue * tx_queue;
+#endif
 
   u8                  irq;
   u8                  flags;
@@ -465,6 +470,8 @@
 typedef struct hrz_dev hrz_dev;
 
 /* macros for use later */
+
+#define BUF_PTR(cbptr) ((cbptr) - (cell_buf *) 0)
 
 #define INTERESTING_INTERRUPTS \
   (RX_DATA_AV | RX_DISABLED | TX_BUS_MASTER_COMPLETE | RX_BUS_MASTER_COMPLETE)
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c
--- v2.3.17/linux/drivers/atm/nicstar.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/atm/nicstar.c	Wed Sep  8 11:14:31 1999
@@ -252,8 +252,7 @@
 #endif /* PHY_LOOPBACK */
    XPRINTK("nicstar: init_module() returned.\n");
 
-   ns_timer.next = NULL;
-   ns_timer.prev = NULL;
+   init_timer(&ns_timer);
    ns_timer.expires = jiffies + NS_POLL_PERIOD;
    ns_timer.data = 0UL;
    ns_timer.function = ns_poll;
@@ -383,6 +382,11 @@
 #endif /* PHY_LOOPBACK */
    XPRINTK("nicstar: init_module() returned.\n");
 
+   init_timer(&ns_timer);
+   ns_timer.expires = jiffies + NS_POLL_PERIOD;
+   ns_timer.data = 0UL;
+   ns_timer.function = ns_poll;
+   add_timer(&ns_timer);
    return i;
 }
 
@@ -845,21 +849,6 @@
       ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
 
    card->efbie = 1;
-   writel(NS_CFG_RXPATH |
-          NS_CFG_SMBUFSIZE |
-          NS_CFG_LGBUFSIZE |
-          NS_CFG_EFBIE |
-          NS_CFG_RSQSIZE |
-          NS_CFG_VPIBITS |
-          ns_cfg_rctsize |
-          NS_CFG_RXINT_NODELAY |
-          NS_CFG_RAWIE |		/* Only enabled if RCQ_SUPPORT */
-          NS_CFG_RSQAFIE |
-          NS_CFG_TXEN |
-          NS_CFG_TXIE |
-          NS_CFG_TSQFIE_OPT |		/* Only enabled if ENABLE_TSQFIE */ 
-          NS_CFG_PHYIE,
-          card->membase + CFG);
 
    /* Register device */
    card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL);
@@ -884,6 +873,7 @@
    card->atmdev->ci_range.vci_bits = card->vcibits;
    card->atmdev->link_rate = card->max_pcr;
 
+   card->atmdev->phy = NULL;
 #ifdef CONFIG_ATM_NICSTAR_USE_SUNI
    if (card->max_pcr == ATM_OC3_PCR) {
       suni_init(card->atmdev);
@@ -896,6 +886,22 @@
    if (card->atmdev->phy && card->atmdev->phy->start)
       card->atmdev->phy->start(card->atmdev);
 
+   writel(NS_CFG_RXPATH |
+          NS_CFG_SMBUFSIZE |
+          NS_CFG_LGBUFSIZE |
+          NS_CFG_EFBIE |
+          NS_CFG_RSQSIZE |
+          NS_CFG_VPIBITS |
+          ns_cfg_rctsize |
+          NS_CFG_RXINT_NODELAY |
+          NS_CFG_RAWIE |		/* Only enabled if RCQ_SUPPORT */
+          NS_CFG_RSQAFIE |
+          NS_CFG_TXEN |
+          NS_CFG_TXIE |
+          NS_CFG_TSQFIE_OPT |		/* Only enabled if ENABLE_TSQFIE */ 
+          NS_CFG_PHYIE,
+          card->membase + CFG);
+
    num_cards++;
 
    return error;
@@ -1132,10 +1138,10 @@
       save_flags(flags); cli();
 
       while (CMD_BUSY(card));
-      writel(handle1, card->membase + DR0);
-      writel(addr1, card->membase + DR1);
-      writel(handle2, card->membase + DR2);
       writel(addr2, card->membase + DR3);
+      writel(handle2, card->membase + DR2);
+      writel(addr1, card->membase + DR1);
+      writel(handle1, card->membase + DR0);
       writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD);
  
       restore_flags(flags);
@@ -3010,7 +3016,7 @@
 {
    if (c >= '0' && c <= '9')
       return (short) (c - '0');
-   if (c >= 'A' && c <= 'A')
+   if (c >= 'A' && c <= 'F')
       return (short) (c - 'A' + 10);
    if (c >= 'a' && c <= 'f')
       return (short) (c - 'a' + 10);
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/nicstar.c.old_skb linux/drivers/atm/nicstar.c.old_skb
--- v2.3.17/linux/drivers/atm/nicstar.c.old_skb	Thu Aug 26 13:05:34 1999
+++ linux/drivers/atm/nicstar.c.old_skb	Wed Dec 31 16:00:00 1969
@@ -1,2883 +0,0 @@
-/******************************************************************************
- *
- * nicstar.c
- *
- * Device driver supporting CBR for NICStAR based cards.
- *
- * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME.
- *            It was taken from the frle-0.22 device driver.
- *            As the file doesn't have a copyright notice, in the file
- *            nicstarmac.copyright I put the copyright notice from the
- *            frle-0.22 device driver.
- *            Some code is based on the nicstar driver by M. Welsh.
- *
- * Author: Rui Prior
- *
- * (C) INESC 1998
- *
- ******************************************************************************/
-
-
-/* Header files ***************************************************************/
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/atmdev.h>
-#include <linux/atm.h>
-#include <linux/pci.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include "nicstar.h"
-#include "nicstarmac.h"
-
-
-/* Additional code ************************************************************/
-
-#include "nicstarmac.c"
-
-
-/* Configurable parameters ****************************************************/
-
-#undef PHY_LOOPBACK
-#undef TX_DEBUG
-#undef RX_DEBUG
-#undef GENERAL_DEBUG
-#undef EXTRA_DEBUG
-
-#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know
-                             you're going to use only raw ATM */
-
-
-/* Do not touch these *********************************************************/
-
-#ifdef TX_DEBUG
-#define TXPRINTK(args...) printk(args)
-#else
-#define TXPRINTK(args...)
-#endif /* TX_DEBUG */
-
-#ifdef RX_DEBUG
-#define RXPRINTK(args...) printk(args)
-#else
-#define RXPRINTK(args...)
-#endif /* RX_DEBUG */
-
-#ifdef GENERAL_DEBUG
-#define PRINTK(args...) printk(args)
-#else
-#define PRINTK(args...)
-#endif /* GENERAL_DEBUG */
-
-#ifdef EXTRA_DEBUG
-#define XPRINTK(args...) printk(args)
-#else
-#define XPRINTK(args...)
-#endif /* EXTRA_DEBUG */
-
-
-/* Macros *********************************************************************/
-
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
-#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ)
-
-#define NS_DELAY mdelay(1)
-
-#define ALIGN_ADDRESS(addr, alignment) \
-        ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1))
-
-#undef CEIL(d)
-
-
-/* Version definition *********************************************************/
-/*
-#include <linux/version.h>
-char kernel_version[] = UTS_RELEASE;
-*/
-
-/* Function declarations ******************************************************/
-
-static u32 ns_read_sram(ns_dev *card, u32 sram_address);
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count);
-static int ns_init_card(int i, struct pci_dev *pcidev);
-static void ns_init_card_error(ns_dev *card, int error);
-static scq_info *get_scq(int size, u32 scd);
-static void free_scq(scq_info *scq, struct atm_vcc *vcc);
-static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
-                       u32 handle2, u32 addr2);
-static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
-static int ns_open(struct atm_vcc *vcc, short vpi, int vci);
-static void ns_close(struct atm_vcc *vcc);
-static void fill_tst(ns_dev *card, int n, vc_map *vc);
-static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb);
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
-                     struct sk_buff *skb);
-static void process_tsq(ns_dev *card);
-static void drain_scq(ns_dev *card, scq_info *scq, int pos);
-static void process_rsq(ns_dev *card);
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe);
-#ifdef NS_USE_DESTRUCTORS
-static void ns_sb_destructor(struct sk_buff *sb);
-static void ns_lb_destructor(struct sk_buff *lb);
-static void ns_hb_destructor(struct sk_buff *hb);
-#endif /* NS_USE_DESTRUCTORS */
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb);
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count);
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb);
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb);
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb);
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page);
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg);
-static void which_list(ns_dev *card, struct sk_buff *skb);
-static void ns_poll(unsigned long arg);
-
-
-/* Global variables ***********************************************************/
-
-static struct ns_dev *cards[NS_MAX_CARDS];
-static unsigned num_cards = 0;
-static struct atmdev_ops atm_ops =
-{
-   NULL,		/* dev_close */
-   ns_open,		/* open */
-   ns_close,		/* close */
-   ns_ioctl,		/* ioctl */
-   NULL,		/* getsockopt */
-   NULL,		/* setsockopt */
-   ns_send,		/* send */
-   NULL,		/* sg_send */
-   NULL,		/* send_oam */
-   NULL,		/* phy_put */
-   NULL,		/* phy_get */
-   NULL,		/* feedback */
-   NULL,		/* change_qos */
-   NULL,		/* free_rx_skb */
-   ns_proc_read		/* proc_read */
-};
-static struct timer_list ns_timer;
-
-
-/* Functions*******************************************************************/
-
-#ifdef MODULE
-
-int init_module(void)
-{
-   int i;
-   unsigned error = 0;	/* Initialized to remove compile warning */
-   struct pci_dev *pcidev;
-
-   XPRINTK("nicstar: init_module() called.\n");
-   if(!pci_present())
-   {
-      printk("nicstar: no PCI subsystem found.\n");
-      return -EIO;
-   }
-
-   for(i = 0; i < NS_MAX_CARDS; i++)
-      cards[i] = NULL;
-
-   pcidev = NULL;
-   for(i = 0; i < NS_MAX_CARDS; i++)
-   {
-      if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT,
-                                    PCI_DEVICE_ID_IDT_IDT77201,
-                                    pcidev)) == NULL)
-         break;
-
-      error = ns_init_card(i, pcidev);
-      if (error)
-         i--;		/* Try to find another card but don't increment index */
-   }
-
-   if (i == 0)
-   {
-      if (!error)
-      {
-         printk("nicstar: no cards found.\n");
-         return -ENXIO;
-      }
-      else
-         return -EIO;
-   }
-   TXPRINTK("nicstar: TX debug enabled.\n");
-   RXPRINTK("nicstar: RX debug enabled.\n");
-   PRINTK("nicstar: General debug enabled.\n");
-#ifdef PHY_LOOPBACK
-   printk("nicstar: using PHY loopback.\n");
-#endif /* PHY_LOOPBACK */
-   XPRINTK("nicstar: init_module() returned.\n");
-
-   ns_timer.next = NULL;
-   ns_timer.prev = NULL;
-   ns_timer.expires = jiffies + NS_POLL_PERIOD;
-   ns_timer.data = 0UL;
-   ns_timer.function = ns_poll;
-   add_timer(&ns_timer);
-   return 0;
-}
-
-
-
-void cleanup_module(void)
-{
-   int i, j;
-   unsigned short pci_command;
-   ns_dev *card;
-   struct sk_buff *hb;
-   struct sk_buff *iovb;
-   struct sk_buff *lb;
-   struct sk_buff *sb;
-   
-   XPRINTK("nicstar: cleanup_module() called.\n");
-
-   if (MOD_IN_USE)
-      printk("nicstar: module in use, remove delayed.\n");
-
-   del_timer(&ns_timer);
-
-   for (i = 0; i < NS_MAX_CARDS; i++)
-   {
-      if (cards[i] == NULL)
-         continue;
-
-      card = cards[i];
-
-      /* Stop everything */
-      writel(0x00000000, card->membase + CFG);
-
-      /* De-register device */
-      atm_dev_deregister(card->atmdev);
-
-      /* Disable memory mapping and busmastering */
-      if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command) != 0)
-      {
-         printk("nicstar%d: can't read PCI_COMMAND.\n", i);
-      }
-      pci_command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-      if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command) != 0)
-      {
-         printk("nicstar%d: can't write PCI_COMMAND.\n", i);
-      }
-      
-      /* Free up resources */
-      j = 0;
-      PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
-      while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
-      {
-         kfree_skb(hb);
-	 j++;
-      }
-      PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
-      j = 0;
-      PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);
-      while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
-      {
-         kfree_skb(iovb);
-         j++;
-      }
-      PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
-      while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
-         kfree_skb(lb);
-      while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
-         kfree_skb(sb);
-      free_scq(card->scq0, NULL);
-      for (j = 0; j < NS_FRSCD_NUM; j++)
-      {
-         if (card->scd2vc[j] != NULL)
-	    free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
-      }
-      kfree(card->rsq.org);
-      kfree(card->tsq.org);
-      free_irq(card->pcidev->irq, card);
-      iounmap((void *) card->membase);
-      kfree(card);
-      
-   }
-   XPRINTK("nicstar: cleanup_module() returned.\n");
-}
-
-
-#else
-
-__initfunc(int nicstar_detect(void))
-{
-   int i;
-   unsigned error = 0;	/* Initialized to remove compile warning */
-   struct pci_dev *pcidev;
-
-   if(!pci_present())
-   {
-      printk("nicstar: no PCI subsystem found.\n");
-      return -EIO;
-   }
-
-   for(i = 0; i < NS_MAX_CARDS; i++)
-      cards[i] = NULL;
-
-   pcidev = NULL;
-   for(i = 0; i < NS_MAX_CARDS; i++)
-   {
-      if ((pcidev = pci_find_device(PCI_VENDOR_ID_IDT,
-                                    PCI_DEVICE_ID_IDT_IDT77201,
-                                    pcidev)) == NULL)
-         break;
-
-      error = ns_init_card(i, pcidev);
-      if (error)
-         i--;		/* Try to find another card but don't increment index */
-   }
-
-   if (i == 0 && error)
-      return -EIO;
-
-   TXPRINTK("nicstar: TX debug enabled.\n");
-   RXPRINTK("nicstar: RX debug enabled.\n");
-   PRINTK("nicstar: General debug enabled.\n");
-#ifdef PHY_LOOPBACK
-   printk("nicstar: using PHY loopback.\n");
-#endif /* PHY_LOOPBACK */
-   XPRINTK("nicstar: init_module() returned.\n");
-
-   return i;
-}
-
-
-#endif /* MODULE */
-
-
-static u32 ns_read_sram(ns_dev *card, u32 sram_address)
-{
-   unsigned long flags;
-   u32 data;
-   sram_address <<= 2;
-   sram_address &= 0x0007FFFC;	/* address must be dword aligned */
-   sram_address |= 0x50000000;	/* SRAM read command */
-   save_flags(flags); cli();
-   while (CMD_BUSY(card));
-   writel(sram_address, card->membase + CMD);
-   while (CMD_BUSY(card));
-   data = readl(card->membase + DR0);
-   restore_flags(flags);
-   return data;
-}
-
-
-   
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count)
-{
-   unsigned long flags;
-   int i, c;
-   count--;	/* count range now is 0..3 instead of 1..4 */
-   c = count;
-   c <<= 2;	/* to use increments of 4 */
-   save_flags(flags); cli();
-   while (CMD_BUSY(card));
-   for (i = 0; i <= c; i += 4)
-      writel(*(value++), card->membase + i);
-   /* Note: DR# registers are the first 4 dwords in nicstar's memspace,
-            so card->membase + DR0 == card->membase */
-   sram_address <<= 2;
-   sram_address &= 0x0007FFFC;
-   sram_address |= (0x40000000 | count);
-   writel(sram_address, card->membase + CMD);
-   restore_flags(flags);
-}
-
-
-static int ns_init_card(int i, struct pci_dev *pcidev)
-{
-   int j;
-   struct ns_dev *card;
-   unsigned short pci_command;
-   unsigned char pci_latency;
-   unsigned error;
-   u32 data;
-   u32 u32d[4];
-   u32 ns_cfg_rctsize;
-   int bcount;
-
-   error = 0;
-
-   if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL)
-   {
-      printk("nicstar%d: can't allocate memory for device structure.\n", i);
-      error = 2;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   cards[i] = card;
-      
-   card->index = i;
-   card->pcidev = pcidev;
-   card->membase = (u32) (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
-   card->membase = (u32) ioremap(card->membase, NS_IOREMAP_SIZE);
-   if (card->membase == (u32) (NULL))
-   {
-      printk("nicstar%d: can't ioremap() membase.\n",i);
-      error = 3;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase);
-
-   if (pci_read_config_word(pcidev, PCI_COMMAND, &pci_command) != 0)
-   {
-      printk("nicstar%d: can't read PCI_COMMAND.\n", i);
-      error = 4;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-   if (pci_write_config_word(pcidev, PCI_COMMAND, pci_command) != 0)
-   {
-      printk("nicstar%d: can't write PCI_COMMAND.\n", i);
-      error = 5;
-      ns_init_card_error(card, error);
-      return error;
-   }
-
-   if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0)
-   {
-      printk("nicstar%d: can't read PCI latency timer.\n", i);
-      error = 6;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   if (pci_latency < NS_PCI_LATENCY)
-   {
-      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);
-	    break;
-      }
-      if (j == 10)
-      {
-         printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
-         error = 7;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-   }
-      
-   /* Clear timer overflow */
-   data = readl(card->membase + STAT);
-   if (data & NS_STAT_TMROF)
-      writel(NS_STAT_TMROF, card->membase + STAT);
-
-   /* Software reset */
-   writel(NS_CFG_SWRST, card->membase + CFG);
-   NS_DELAY;
-   writel(0x00000000, card->membase + CFG);
-
-   /* PHY reset */
-   writel(0x00000008, card->membase + GP);
-   NS_DELAY;
-   writel(0x00000001, card->membase + GP);
-   NS_DELAY;
-   while (CMD_BUSY(card));
-   writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD);	/* Sync UTOPIA with SAR clock */
-   NS_DELAY;
-      
-   /* Detect PHY type */
-   while (CMD_BUSY(card));
-   writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD);
-   while (CMD_BUSY(card));
-   data = readl(card->membase + DR0);
-   if (data == 0x00000009)
-   {
-      printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
-      card->max_pcr = IDT_25_PCR;
-      while(CMD_BUSY(card));
-      writel(0x00000008, card->membase + DR0);
-      writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
-      /* Clear an eventual pending interrupt */
-      writel(NS_STAT_SFBQF, card->membase + STAT);
-#ifdef PHY_LOOPBACK
-      while(CMD_BUSY(card));
-      writel(0x00000022, card->membase + DR0);
-      writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD);
-#endif /* PHY_LOOPBACK */
-   }
-   else if (data == 0x00000030)
-   {
-      printk("nicstar%d: PHY seems to be 155 Mbps.\n", i);
-      card->max_pcr = ATM_OC3_PCR;
-#ifdef PHY_LOOPBACK
-      while(CMD_BUSY(card));
-      writel(0x00000002, card->membase + DR0);
-      writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD);
-#endif /* PHY_LOOPBACK */
-   }
-   else
-   {
-      printk("nicstar%d: can't determine PHY type.\n", i);
-      error = 8;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   writel(0x00000000, card->membase + GP);
-
-   /* Determine SRAM size */
-   data = 0x76543210;
-   ns_write_sram(card, 0x1C003, &data, 1);
-   data = 0x89ABCDEF;
-   ns_write_sram(card, 0x14003, &data, 1);
-   if (ns_read_sram(card, 0x14003) == 0x89ABCDEF &&
-       ns_read_sram(card, 0x1C003) == 0x76543210)
-       card->sram_size = 128;
-   else
-      card->sram_size = 32;
-   PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size);
-
-   card->rct_size = NS_MAX_RCTSIZE;
-
-#if (NS_MAX_RCTSIZE == 4096)
-   if (card->sram_size == 128)
-      printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i);
-#elif (NS_MAX_RCTSIZE == 16384)
-   if (card->sram_size == 32)
-   {
-      printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i);
-      card->rct_size = 4096;
-   }
-#else
-#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c
-#endif
-
-   card->vpibits = NS_VPIBITS;
-   if (card->rct_size == 4096)
-      card->vcibits = 12 - NS_VPIBITS;
-   else /* card->rct_size == 16384 */
-      card->vcibits = 14 - NS_VPIBITS;
-
-#ifdef ESI_FROM_EPROM
-   /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */
-   nicstar_init_eprom(card->membase);
-#endif /* ESI_FROM_EPROM */
-
-   if (request_irq(pcidev->irq, &ns_irq_handler, SA_INTERRUPT, "nicstar", card) != 0)
-   {
-      printk("nicstar%d: can't allocate IRQ.\n", i);
-      error = 9;
-      ns_init_card_error(card, error);
-      return error;
-   }
-
-   /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
-   writel(0x00000000, card->membase + VPM);
-      
-   /* Initialize TSQ */
-   card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL);
-   if (card->tsq.org == NULL)
-   {
-      printk("nicstar%d: can't allocate TSQ.\n", i);
-      error = 10;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT);
-   card->tsq.next = card->tsq.base;
-   card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1);
-   for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++)
-      ns_tsi_init(card->tsq.base + j);
-   writel(0x00000000, card->membase + TSQH);
-   writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB);
-   PRINTK("nicstar%d: TSQ base at 0x%x  0x%x  0x%x.\n", i, (u32) card->tsq.base,
-          (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB));
-      
-   /* Initialize RSQ */
-   card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL);
-   if (card->rsq.org == NULL)
-   {
-      printk("nicstar%d: can't allocate RSQ.\n", i);
-      error = 11;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT);
-   card->rsq.next = card->rsq.base;
-   card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1);
-   for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++)
-      ns_rsqe_init(card->rsq.base + j);
-   writel(0x00000000, card->membase + RSQH);
-   writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB);
-   PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
-      
-   /* Initialize SCQ0, the only VBR SCQ used */
-   card->scq1 = (scq_info *) NULL;
-   card->scq2 = (scq_info *) NULL;
-   card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
-   if (card->scq0 == (scq_info *) NULL)
-   {
-      printk("nicstar%d: can't get SCQ0.\n", i);
-      error = 12;
-      ns_init_card_error(card, error);
-      return error;
-   }
-   u32d[0] = (u32) virt_to_bus(card->scq0->base);
-   u32d[1] = (u32) 0x00000000;
-   u32d[2] = (u32) 0xffffffff;
-   u32d[3] = (u32) 0x00000000;
-   ns_write_sram(card, NS_VRSCD0, u32d, 4);
-   ns_write_sram(card, NS_VRSCD1, u32d, 4);	/* These last two won't be used */
-   ns_write_sram(card, NS_VRSCD2, u32d, 4);	/* but are initialized, just in case... */
-   card->scq0->scd = NS_VRSCD0;
-   PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base);
-
-   /* Initialize TSTs */
-   card->tst_addr = NS_TST0;
-   card->tst_free_entries = NS_TST_NUM_ENTRIES;
-   data = NS_TST_OPCODE_VARIABLE;
-   for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
-      ns_write_sram(card, NS_TST0 + j, &data, 1);
-   data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0);
-   ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1);
-   for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
-      ns_write_sram(card, NS_TST1 + j, &data, 1);
-   data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1);
-   ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1);
-   for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
-      card->tste2vc[j] = NULL;
-   writel(NS_TST0 << 2, card->membase + TSTB);
-
-
-   /* Initialize RCT. AAL type is set on opening the VC. */
-#ifdef RCQ_SUPPORT
-   u32d[0] = NS_RCTE_RAWCELLINTEN;
-#else
-   u32d[0] = 0x00000000;
-#endif RCQ_SUPPORT
-   u32d[1] = 0x00000000;
-   u32d[2] = 0x00000000;
-   u32d[3] = 0xFFFFFFFF;
-   for (j = 0; j < card->rct_size; j++)
-      ns_write_sram(card, j * 4, u32d, 4);      
-      
-   memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map));
-      
-   for (j = 0; j < NS_FRSCD_NUM; j++)
-      card->scd2vc[j] = NULL;
-
-   /* Initialize buffer levels */
-   card->sbnr.min = MIN_SB;
-   card->sbnr.init = NUM_SB;
-   card->sbnr.max = MAX_SB;
-   card->lbnr.min = MIN_LB;
-   card->lbnr.init = NUM_LB;
-   card->lbnr.max = MAX_LB;
-   card->iovnr.min = MIN_IOVB;
-   card->iovnr.init = NUM_IOVB;
-   card->iovnr.max = MAX_IOVB;
-   card->hbnr.min = MIN_HB;
-   card->hbnr.init = NUM_HB;
-   card->hbnr.max = MAX_HB;
-   
-   card->sm_handle = 0x00000000;
-   card->sm_addr = 0x00000000;
-   card->lg_handle = 0x00000000;
-   card->lg_addr = 0x00000000;
-   
-   card->efbie = 1;	/* To prevent push_rxbufs from enabling the interrupt */
-
-   /* Allocate small buffers */
-   skb_queue_head_init(&card->sbpool.queue);
-   card->sbpool.count = 0;			/* Not used */
-   for (j = 0; j < NUM_SB; j++)
-   {
-      struct sk_buff *sb;
-      sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
-      if (sb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d small buffers.\n",
-                i, j, NUM_SB);
-         error = 13;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      skb_queue_tail(&card->sbpool.queue, sb);
-      skb_reserve(sb, NS_AAL0_HEADER);
-      push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
-   }
-   /* Test for strange behaviour which leads to crashes */
-   if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min)
-   {
-      printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n",
-             i, j, bcount);
-      error = 13;
-      ns_init_card_error(card, error);
-      return error;
-   }
-      
-
-   /* Allocate large buffers */
-   skb_queue_head_init(&card->lbpool.queue);
-   card->lbpool.count = 0;			/* Not used */
-   for (j = 0; j < NUM_LB; j++)
-   {
-      struct sk_buff *lb;
-      lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
-      if (lb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d large buffers.\n",
-                i, j, NUM_LB);
-         error = 14;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      skb_queue_tail(&card->lbpool.queue, lb);
-      skb_reserve(lb, NS_SMBUFSIZE);
-      push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
-      /* Due to the implementation of push_rxbufs() this is 1, not 0 */
-      if (j == 1)
-      {
-         card->rcbuf = lb;
-         card->rawch = (u32) virt_to_bus(lb->data);
-      }
-   }
-   /* Test for strange behaviour which leads to crashes */
-   if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min)
-   {
-      printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n",
-             i, j, bcount);
-      error = 14;
-      ns_init_card_error(card, error);
-      return error;
-   }
-      
-
-   /* Allocate iovec buffers */
-   skb_queue_head_init(&card->iovpool.queue);
-   card->iovpool.count = 0;
-   for (j = 0; j < NUM_IOVB; j++)
-   {
-      struct sk_buff *iovb;
-      iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
-      if (iovb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n",
-                i, j, NUM_IOVB);
-         error = 15;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      skb_queue_tail(&card->iovpool.queue, iovb);
-      card->iovpool.count++;
-   }
-
-
-   /* Pre-allocate some huge buffers */
-   skb_queue_head_init(&card->hbpool.queue);
-   card->hbpool.count = 0;
-   for (j = 0; j < NUM_HB; j++)
-   {
-      struct sk_buff *hb;
-      hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
-      if (hb == NULL)
-      {
-         printk("nicstar%d: can't allocate %dth of %d huge buffers.\n",
-                i, j, NUM_HB);
-         error = 16;
-         ns_init_card_error(card, error);
-	 return error;
-      }
-      skb_queue_tail(&card->hbpool.queue, hb);
-      card->hbpool.count++;
-   }
-
-   card->in_handler = 0;
-   card->in_poll = 0;
-   card->intcnt = 0;
-
-   /* Configure NICStAR */
-   if (card->rct_size == 4096)
-      ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
-   else /* (card->rct_size == 16384) */
-      ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
-
-   card->efbie = 1;
-   writel(NS_CFG_RXPATH |
-          NS_CFG_SMBUFSIZE |
-          NS_CFG_LGBUFSIZE |
-          NS_CFG_EFBIE |
-          NS_CFG_RSQSIZE |
-          NS_CFG_VPIBITS |
-          ns_cfg_rctsize |
-          NS_CFG_RXINT_NODELAY |
-          NS_CFG_RAWIE |		/* Only enabled if RCQ_SUPPORT */
-          NS_CFG_RSQAFIE |
-          NS_CFG_TXEN |
-          NS_CFG_TXIE |
-          NS_CFG_TSQFIE_OPT,		/* Only enabled if ENABLE_TSQFIE */ 
-          card->membase + CFG);
-
-   /* Register device */
-   card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, 0UL);
-   if (card->atmdev == NULL)
-   {
-      printk("nicstar%d: can't register device.\n", i);
-      error = 17;
-      ns_init_card_error(card, error);
-      return error;
-   }
-      
-#ifdef ESI_FROM_EPROM
-   nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
-                      card->atmdev->esi, 6);
-   printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i,
-          card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2],
-          card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]);
-#else
-   card->atmdev->esi[0] = NS_ESI0;
-   card->atmdev->esi[1] = NS_ESI1;
-   card->atmdev->esi[2] = NS_ESI2;
-   card->atmdev->esi[3] = NS_ESI3;
-   card->atmdev->esi[4] = NS_ESI4;
-   card->atmdev->esi[5] = NS_ESI5;
-#endif /* ESI_FROM_EPROM */
-
-   card->atmdev->dev_data = card;
-   card->atmdev->ci_range.vpi_bits = card->vpibits;
-   card->atmdev->ci_range.vci_bits = card->vcibits;
-
-   num_cards++;
-
-   return error;
-}
-
-
-
-static void ns_init_card_error(ns_dev *card, int error)
-{
-   if (error >= 17)
-   {
-      writel(0x00000000, card->membase + CFG);
-   }
-   if (error >= 16)
-   {
-      struct sk_buff *hb;
-      while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
-         kfree_skb(hb);
-   }
-   if (error >= 15)
-   {
-      struct sk_buff *iovb;
-      while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
-         kfree_skb(iovb);
-   }
-   if (error >= 14)
-   {
-      struct sk_buff *lb;
-      while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
-         kfree_skb(lb);
-   }
-   if (error >= 13)
-   {
-      struct sk_buff *sb;
-      while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
-         kfree_skb(sb);
-      free_scq(card->scq0, NULL);
-   }
-   if (error >= 12)
-   {
-      kfree(card->rsq.org);
-   }
-   if (error >= 11)
-   {
-      kfree(card->tsq.org);
-   }
-   if (error >= 10)
-   {
-      free_irq(card->pcidev->irq, card);
-   }
-   if (error >= 4)
-   {
-      iounmap((void *) card->membase);
-   }
-   if (error >= 3)
-   {
-      kfree(card);
-   }
-}
-
-
-
-static scq_info *get_scq(int size, u32 scd)
-{
-   scq_info *scq;
-   int i;
-
-   if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
-      return (scq_info *) NULL;
-
-   scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);
-   if (scq == (scq_info *) NULL)
-      return (scq_info *) NULL;
-   scq->org = kmalloc(2 * size, GFP_KERNEL);
-   if (scq->org == NULL)
-   {
-      kfree(scq);
-      return (scq_info *) NULL;
-   }
-   scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *
-                                          (size / NS_SCQE_SIZE), GFP_KERNEL);
-   if (scq->skb == (struct sk_buff **) NULL)
-   {
-      kfree(scq->org);
-      kfree(scq);
-      return (scq_info *) NULL;
-   }
-   scq->num_entries = size / NS_SCQE_SIZE;
-   scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
-   scq->next = scq->base;
-   scq->last = scq->base + (scq->num_entries - 1);
-   scq->tail = scq->last;
-   scq->scd = scd;
-   scq->num_entries = size / NS_SCQE_SIZE;
-   scq->tbd_count = 0;
-   scq->scqfull_waitq = NULL;
-   scq->full = 0;
-
-   for (i = 0; i < scq->num_entries; i++)
-      scq->skb[i] = NULL;
-
-   return scq;
-}
-
-
-
-/* For variable rate SCQ vcc must be NULL */
-static void free_scq(scq_info *scq, struct atm_vcc *vcc)
-{
-   int i;
-
-   if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
-      for (i = 0; i < scq->num_entries; i++)
-      {
-         if (scq->skb[i] != NULL)
-	 {
-            vcc = scq->skb[i]->atm.vcc;
-            if (vcc->pop != NULL)
-	       vcc->pop(vcc, scq->skb[i]);
-	    else
-               dev_kfree_skb(scq->skb[i]);
-         }
-      }
-   else /* vcc must be != NULL */
-   {
-      if (vcc == NULL)
-      {
-         printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
-         for (i = 0; i < scq->num_entries; i++)
-            dev_kfree_skb(scq->skb[i]);
-      }
-      else
-         for (i = 0; i < scq->num_entries; i++)
-         {
-            if (scq->skb[i] != NULL)
-            {
-               if (vcc->pop != NULL)
-                  vcc->pop(vcc, scq->skb[i]);
-               else
-                  dev_kfree_skb(scq->skb[i]);
-            }
-         }
-   }
-   kfree(scq->skb);
-   kfree(scq->org);
-   kfree(scq);
-}
-
-
-
-/* The handles passed must be pointers to the sk_buff containing the small
-   or large buffer(s) cast to u32. */
-static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,
-                       u32 handle2, u32 addr2)
-{
-   u32 stat;
-   unsigned long flags;
-   
-
-#ifdef GENERAL_DEBUG
-   if (!addr1)
-      printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index);
-#endif /* GENERAL_DEBUG */
-
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);
-   card->lbfqc = ns_stat_lfbqc_get(stat);
-   if (type == BUF_SM)
-   {
-      if (!addr2)
-      {
-         if (card->sm_addr)
-	 {
-	    addr2 = card->sm_addr;
-	    handle2 = card->sm_handle;
-	    card->sm_addr = 0x00000000;
-	    card->sm_handle = 0x00000000;
-	 }
-	 else /* (!sm_addr) */
-	 {
-	    card->sm_addr = addr1;
-	    card->sm_handle = handle1;
-	 }
-      }      
-   }
-   else /* type == BUF_LG */
-   {
-      if (!addr2)
-      {
-         if (card->lg_addr)
-	 {
-	    addr2 = card->lg_addr;
-	    handle2 = card->lg_handle;
-	    card->lg_addr = 0x00000000;
-	    card->lg_handle = 0x00000000;
-	 }
-	 else /* (!lg_addr) */
-	 {
-	    card->lg_addr = addr1;
-	    card->lg_handle = handle1;
-	 }
-      }      
-   }
-
-   if (addr2)
-   {
-      if (type == BUF_SM)
-      {
-         if (card->sbfqc >= card->sbnr.max)
-         {
-            skb_unlink((struct sk_buff *) handle1);
-            kfree_skb((struct sk_buff *) handle1);
-            skb_unlink((struct sk_buff *) handle2);
-            kfree_skb((struct sk_buff *) handle2);
-            return;
-         }
-	 else
-            card->sbfqc += 2;
-      }
-      else /* (type == BUF_LG) */
-      {
-         if (card->lbfqc >= card->lbnr.max)
-         {
-            skb_unlink((struct sk_buff *) handle1);
-            kfree_skb((struct sk_buff *) handle1);
-            skb_unlink((struct sk_buff *) handle2);
-            kfree_skb((struct sk_buff *) handle2);
-            return;
-         }
-         else
-            card->lbfqc += 2;
-      }
-
-      save_flags(flags); cli();
-
-      while (CMD_BUSY(card));
-      writel(handle1, card->membase + DR0);
-      writel(addr1, card->membase + DR1);
-      writel(handle2, card->membase + DR2);
-      writel(addr2, card->membase + DR3);
-      writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD);
- 
-      restore_flags(flags);
-
-      XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index,
-              (type == BUF_SM ? "small" : "large"), addr1, addr2);
-   }
-
-   if (!card->efbie && card->sbfqc >= card->sbnr.min &&
-       card->lbfqc >= card->lbnr.min)
-   {
-      card->efbie = 1;
-      writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG);
-   }
-
-   return;
-}
-
-
-
-static void ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-   u32 stat_r;
-   ns_dev *card;
-
-   card = (ns_dev *) dev_id;
-   card->intcnt++;
-
-   PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
-
-   if (card->in_handler)
-   {
-      printk("nicstar%d: Re-entering ns_irq_handler()???\n", card->index);
-      return;
-   }
-   card->in_handler = 1;
-   if (card->in_poll)
-   {
-      card->in_handler = 0;
-      printk("nicstar%d: Called irq handler while in ns_poll()!?\n",
-             card->index);
-      return;
-   }
-   
-   stat_r = readl(card->membase + STAT);
-
-   /* Transmit Status Indicator has been written to T. S. Queue */
-   if (stat_r & NS_STAT_TSIF)
-   {
-      TXPRINTK("nicstar%d: TSI interrupt\n", card->index);
-      process_tsq(card);
-      writel(NS_STAT_TSIF, card->membase + STAT);
-   }
-   
-   /* Incomplete CS-PDU has been transmitted */
-   if (stat_r & NS_STAT_TXICP)
-   {
-      writel(NS_STAT_TXICP, card->membase + STAT);
-      TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",
-               card->index);
-   }
-   
-   /* Transmit Status Queue 7/8 full */
-   if (stat_r & NS_STAT_TSQF)
-   {
-      writel(NS_STAT_TSQF, card->membase + STAT);
-      PRINTK("nicstar%d: TSQ full.\n", card->index);
-      process_tsq(card);
-   }
-   
-   /* Timer overflow */
-   if (stat_r & NS_STAT_TMROF)
-   {
-      writel(NS_STAT_TMROF, card->membase + STAT);
-      PRINTK("nicstar%d: Timer overflow.\n", card->index);
-   }
-   
-   /* PHY device interrupt signal active */
-   if (stat_r & NS_STAT_PHYI)
-   {
-      writel(NS_STAT_PHYI, card->membase + STAT);
-      printk("nicstar%d: PHY interrupt.\n", card->index);
-   }
-
-   /* Small Buffer Queue is full */
-   if (stat_r & NS_STAT_SFBQF)
-   {
-      writel(NS_STAT_SFBQF, card->membase + STAT);
-      printk("nicstar%d: Small free buffer queue is full.\n", card->index);
-   }
-   
-   /* Large Buffer Queue is full */
-   if (stat_r & NS_STAT_LFBQF)
-   {
-      writel(NS_STAT_LFBQF, card->membase + STAT);
-      printk("nicstar%d: Large free buffer queue is full.\n", card->index);
-   }
-
-   /* Receive Status Queue is full */
-   if (stat_r & NS_STAT_RSQF)
-   {
-      writel(NS_STAT_RSQF, card->membase + STAT);
-      printk("nicstar%d: RSQ full.\n", card->index);
-      process_rsq(card);
-   }
-
-   /* Complete CS-PDU received */
-   if (stat_r & NS_STAT_EOPDU)
-   {
-      RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index);
-      process_rsq(card);
-      writel(NS_STAT_EOPDU, card->membase + STAT);
-   }
-
-   /* Raw cell received */
-   if (stat_r & NS_STAT_RAWCF)
-   {
-      writel(NS_STAT_RAWCF, card->membase + STAT);
-#ifndef RCQ_SUPPORT
-      printk("nicstar%d: Raw cell received and no support yet...\n",
-             card->index);
-#endif /* RCQ_SUPPORT */
-      /* NOTE: the following procedure may keep a raw cell pending untill the
-               next interrupt. As this preliminary support is only meant to
-               avoid buffer leakage, this is not an issue. */
-      while (readl(card->membase + RAWCT) != card->rawch)
-      {
-         ns_rcqe *rawcell;
-
-         rawcell = (ns_rcqe *) bus_to_virt(card->rawch);
-         if (ns_rcqe_islast(rawcell))
-         {
-            struct sk_buff *oldbuf;
-
-            oldbuf = card->rcbuf;
-            card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell);
-            card->rawch = (u32) virt_to_bus(card->rcbuf->data);
-            recycle_rx_buf(card, oldbuf);
-         }
-         else
-            card->rawch += NS_RCQE_SIZE;
-      }
-   }
-
-   /* Small buffer queue is empty */
-   if (stat_r & NS_STAT_SFBQE)
-   {
-      int i;
-      struct sk_buff *sb;
-
-      writel(NS_STAT_SFBQE, card->membase + STAT);
-      printk("nicstar%d: Small free buffer queue empty.\n",
-             card->index);
-      for (i = 0; i < card->sbnr.min; i++)
-      {
-         sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC);
-         if (sb == NULL)
-         {
-            writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
-            card->efbie = 0;
-            break;
-         }
-         skb_queue_tail(&card->sbpool.queue, sb);
-         skb_reserve(sb, NS_AAL0_HEADER);
-         push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
-      }
-      card->sbfqc = i;
-      process_rsq(card);
-   }
-
-   /* Large buffer queue empty */
-   if (stat_r & NS_STAT_LFBQE)
-   {
-      int i;
-      struct sk_buff *lb;
-
-      writel(NS_STAT_LFBQE, card->membase + STAT);
-      printk("nicstar%d: Large free buffer queue empty.\n",
-             card->index);
-      for (i = 0; i < card->lbnr.min; i++)
-      {
-         lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC);
-         if (lb == NULL)
-         {
-            writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
-            card->efbie = 0;
-            break;
-         }
-         skb_queue_tail(&card->lbpool.queue, lb);
-         skb_reserve(lb, NS_SMBUFSIZE);
-         push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
-      }
-      card->lbfqc = i;
-      process_rsq(card);
-   }
-
-   /* Receive Status Queue is 7/8 full */
-   if (stat_r & NS_STAT_RSQAF)
-   {
-      writel(NS_STAT_RSQAF, card->membase + STAT);
-      RXPRINTK("nicstar%d: RSQ almost full.\n", card->index);
-      process_rsq(card);
-   }
-   
-   card->in_handler = 0;
-   PRINTK("nicstar%d: end of interrupt service\n", card->index);
-}
-
-
-
-static int ns_open(struct atm_vcc *vcc, short vpi, int vci)
-{
-   ns_dev *card;
-   vc_map *vc;
-   int error;
-   double tmpd;
-   int tcr, tcra;	/* target cell rate, and absolute value */
-   int n = 0;		/* Number of entries in the TST. Initialized to remove
-                           the compiler warning. */
-   u32 u32d[4];
-   int frscdi = 0;	/* Index of the SCD. Initialized to remove the compiler
-                           warning. How I wish compilers were clever enough to
-			   tell which variables can truly be used
-			   uninitialized... */
-   int inuse;		/* tx or rx vc already in use by another vcc */
-
-   card = (ns_dev *) vcc->dev->dev_data;
-   PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci);
-   if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
-   {
-      PRINTK("nicstar%d: unsupported AAL.\n", card->index);
-      return -EINVAL;
-   }
-
-   if ((error = atm_find_ci(vcc, &vpi, &vci)))
-   {
-      PRINTK("nicstar%d: error in atm_find_ci().\n", card->index);
-      return error;
-   }
-   vc = &(card->vcmap[vpi << card->vcibits | vci]);
-   vcc->vpi = vpi;
-   vcc->vci = vci;
-   vcc->dev_data = vc;
-
-   inuse = 0;
-   if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
-      inuse = 1;
-   if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
-      inuse += 2;
-   if (inuse)
-   {
-      printk("nicstar%d: %s vci already in use.\n", card->index,
-             inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
-      return -EINVAL;
-   }
-
-   vcc->flags |= ATM_VF_ADDR;
-
-   /* NOTE: You are not allowed to modify an open connection's QOS. To change
-      that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
-      needed to do that. */
-   if (!(vcc->flags & ATM_VF_PARTIAL))
-   {
-      scq_info *scq;
-      
-      vcc->flags |= ATM_VF_PARTIAL;
-      if (vcc->qos.txtp.traffic_class == ATM_CBR)
-      {
-         /* Check requested cell rate and availability of SCD */
-         if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 &&
-             vcc->qos.txtp.min_pcr == 0)
-         {
-            PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
-	           card->index);
-            vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
-            return -EINVAL;
-         }
-
-         tcr = atm_pcr_goal(&(vcc->qos.txtp));
-         tcra = tcr >= 0 ? tcr : -tcr;
-      
-         PRINTK("nicstar%d: target cell rate = %d.\n", card->index,
-                vcc->qos.txtp.max_pcr);
-
-         tmpd = ((double) tcra) * ((double) NS_TST_NUM_ENTRIES) /
-                ((double) card->max_pcr);      
-
-         n = (int) tmpd;
-         if (tcr > 0)
-         {
-            if (tmpd > (double) n) n++;
-         }
-         else if (tcr < 0)
-         {
-            if (tmpd < (double) n) n--;
-         }
-         else /* tcr == 0 */
-         {
-            if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
-	    {
-               PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index);
-	       vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
-               return -EINVAL;
-            }
-         }
-
-         if (n == 0)
-         {
-            printk("nicstar%d: selected bandwidth < granularity.\n", card->index);
-            vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
-            return -EINVAL;
-         }
-
-         if (vcc->qos.txtp.max_pcr > 0)
-         {
-            tmpd = (double) n * (double) card->max_pcr /
-	           (double) NS_TST_NUM_ENTRIES;
-            if (tmpd > PCR_TOLERANCE * (double) vcc->qos.txtp.max_pcr)
-            {
-               PRINTK("nicstar%d: target cell rate exceeded requested max_pcr.\n",
-                      card->index);
-            }
-         }
-
-         if (n > (card->tst_free_entries - NS_TST_RESERVED))
-         {
-            PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
-	    vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
-            return -EINVAL;
-         }
-         else
-            card->tst_free_entries -= n;
-
-         XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n);
-         for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++)
-         {
-            if (card->scd2vc[frscdi] == NULL)
-            {
-               card->scd2vc[frscdi] = vc;
-               break;
-	    }
-         }
-         if (frscdi == NS_FRSCD_NUM)
-         {
-            PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index);
-            card->tst_free_entries += n;
-            vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
-	    return -EBUSY;
-         }
-
-         vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
-
-         scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
-         if (scq == (scq_info *) NULL)
-         {
-            PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
-            card->scd2vc[frscdi] = NULL;
-            card->tst_free_entries += n;
-            vcc->flags &= ~(ATM_VF_ADDR | ATM_VF_PARTIAL);
-            return -ENOMEM;
-         }
-	 vc->scq = scq;
-         u32d[0] = (u32) virt_to_bus(scq->base);
-         u32d[1] = (u32) 0x00000000;
-         u32d[2] = (u32) 0xffffffff;
-         u32d[3] = (u32) 0x00000000;
-         ns_write_sram(card, vc->cbr_scd, u32d, 4);
-         
-	 fill_tst(card, n, vc);
-      }
-      else /* not CBR */
-      {
-         vc->cbr_scd = 0x00000000;
-	 vc->scq = card->scq0;
-      }
-      
-      if (vcc->qos.txtp.traffic_class != ATM_NONE)
-      {
-         vc->tx = 1;
-	 vc->tx_vcc = vcc;
-	 vc->tbd_count = 0;
-      }
-      if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-      {
-         u32 status;
-      
-         vc->rx = 1;
-         vc->rx_vcc = vcc;
-         vc->rx_iov = NULL;
-
-	 /* Open the connection in hardware */
-	 if (vcc->qos.aal == ATM_AAL5)
-	    status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
-	 else /* vcc->qos.aal == ATM_AAL0 */
-	    status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
-#ifdef RCQ_SUPPORT
-         status |= NS_RCTE_RAWCELLINTEN;
-#endif /* RCQ_SUPPORT */
-         ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) *
-	               NS_RCT_ENTRY_SIZE, &status, 1);
-      }
-      
-   }
-   
-   vcc->flags |= ATM_VF_READY;
-   return 0;
-}
-
-
-
-static void ns_close(struct atm_vcc *vcc)
-{
-   vc_map *vc;
-   ns_dev *card;
-   u32 data;
-   int i;
-   
-   vc = vcc->dev_data;
-   card = vcc->dev->dev_data;
-   PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
-          (int) vcc->vpi, vcc->vci);
-
-   vcc->flags &= ~(ATM_VF_READY);
-   
-   if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-   {
-      u32 addr;
-      unsigned long flags;
-      
-      addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
-      save_flags(flags); cli();
-      while(CMD_BUSY(card));
-      writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD);
-      restore_flags(flags);
-      
-      vc->rx = 0;
-      if (vc->rx_iov != NULL)
-      {
-	 struct sk_buff *iovb;
-	 u32 stat;
-   
-         stat = readl(card->membase + STAT);
-         card->sbfqc = ns_stat_sfbqc_get(stat);   
-         card->lbfqc = ns_stat_lfbqc_get(stat);
-
-         PRINTK("nicstar%d: closing a VC with pending rx buffers.\n",
-	        card->index);
-         iovb = vc->rx_iov;
-         recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                       iovb->atm.iovcnt);
-         iovb->atm.iovcnt = 0;
-         iovb->atm.vcc = NULL;
-         save_flags(flags); cli();
-         recycle_iov_buf(card, iovb);
-         restore_flags(flags);
-         vc->rx_iov = NULL;
-      }
-   }
-
-   if (vcc->qos.txtp.traffic_class != ATM_NONE)
-   {
-      vc->tx = 0;
-   }
-
-   if (vcc->qos.txtp.traffic_class == ATM_CBR)
-   {
-      unsigned long flags;
-      ns_scqe *scqep;
-      scq_info *scq;
-
-      scq = vc->scq;
-
-      for (;;)
-      {
-         save_flags(flags); cli();
-         scqep = scq->next;
-         if (scqep == scq->base)
-            scqep = scq->last;
-         else
-            scqep--;
-         if (scqep == scq->tail)
-         {
-            restore_flags(flags);
-            break;
-         }
-         /* If the last entry is not a TSR, place one in the SCQ in order to
-            be able to completely drain it and then close. */
-         if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next)
-         {
-            ns_scqe tsr;
-            u32 scdi, scqi;
-            u32 data;
-            int index;
-
-            tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
-            scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
-            scqi = scq->next - scq->base;
-            tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
-            tsr.word_3 = 0x00000000;
-            tsr.word_4 = 0x00000000;
-            *scq->next = tsr;
-            index = (int) scqi;
-            scq->skb[index] = NULL;
-            if (scq->next == scq->last)
-               scq->next = scq->base;
-            else
-               scq->next++;
-            data = (u32) virt_to_bus(scq->next);
-            ns_write_sram(card, scq->scd, &data, 1);
-         }
-         schedule();
-         restore_flags(flags);
-      }
-
-      /* Free all TST entries */
-      data = NS_TST_OPCODE_VARIABLE;
-      for (i = 0; i < NS_TST_NUM_ENTRIES; i++)
-      {
-         if (card->tste2vc[i] == vc)
-	 {
-            ns_write_sram(card, card->tst_addr + i, &data, 1);
-            card->tste2vc[i] = NULL;
-            card->tst_free_entries++;
-	 }
-      }
-      
-      card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
-      free_scq(vc->scq, vcc);
-   }
-
-   vcc->dev_data = NULL;
-   vcc->flags &= ~(ATM_VF_PARTIAL | ATM_VF_ADDR);
-
-#ifdef RX_DEBUG
-   {
-      u32 stat, cfg;
-      stat = readl(card->membase + STAT);
-      cfg = readl(card->membase + CFG);
-      printk("STAT = 0x%08X  CFG = 0x%08X  \n", stat, cfg);
-      printk("TSQ: base = 0x%08X  next = 0x%08X  last = 0x%08X  TSQT = 0x%08X \n",
-             (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last,
-	     readl(card->membase + TSQT));
-      printk("RSQ: base = 0x%08X  next = 0x%08X  last = 0x%08X  RSQT = 0x%08X \n",
-             (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last,
-	     readl(card->membase + RSQT));
-      printk("Empty free buffer queue interrupt %s \n",
-             card->efbie ? "enabled" : "disabled");
-      printk("SBCNT = %d  count = %d   LBCNT = %d count = %d \n",
-             ns_stat_sfbqc_get(stat), card->sbpool.count,
-	     ns_stat_lfbqc_get(stat), card->lbpool.count);
-      printk("hbpool.count = %d  iovpool.count = %d \n",
-             card->hbpool.count, card->iovpool.count);
-   }
-#endif /* RX_DEBUG */
-}
-
-
-
-static void fill_tst(ns_dev *card, int n, vc_map *vc)
-{
-   u32 new_tst;
-   double c, q;
-   int e, r;
-   u32 data;
-      
-   /* It would be very complicated to keep the two TSTs synchronized while
-      assuring that writes are only made to the inactive TST. So, for now I
-      will use only one TST. If problems occur, I will change this again */
-   
-   new_tst = card->tst_addr;
-
-   /* Fill procedure */
-
-   for (e = 0; e < NS_TST_NUM_ENTRIES; e++)
-   {
-      if (card->tste2vc[e] == NULL)
-         break;
-   }
-   if (e == NS_TST_NUM_ENTRIES)
-      printk("nicstar%d: No free TST entries found. \n", card->index);
-
-   r = n;
-   c = 1.0;
-   q = (double) n / (double) NS_TST_NUM_ENTRIES;
-
-   data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
-      
-   while (e < NS_TST_NUM_ENTRIES)
-   {
-      if (c >= 1.0 && card->tste2vc[e] == NULL)
-      {
-         card->tste2vc[e] = vc;
-         ns_write_sram(card, new_tst + e, &data, 1);
-	 c -= 1.0;
-	 if (--r == 0)
-	    break;
-      }
-
-      e++;
-      c += q;
-   }
-   if (r != 0)
-      printk("nicstar%d: Not enough free TST entries. CBR lower than requested.\n",
-             card->index);
-   
-   /* End of fill procedure */
-   
-   data = ns_tste_make(NS_TST_OPCODE_END, new_tst);
-   ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1);
-   ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1);
-   card->tst_addr = new_tst;
-}
-
-
-
-static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
-{
-   ns_dev *card;
-   vc_map *vc;
-   scq_info *scq;
-   unsigned long buflen;
-   ns_scqe scqe;
-   u32 flags;		/* TBD flags, not CPU flags */
-   
-   card = vcc->dev->dev_data;
-   TXPRINTK("nicstar%d: ns_send() called.\n", card->index);
-   if ((vc = (vc_map *) vcc->dev_data) == NULL)
-   {
-      printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index);
-      vcc->stats->tx_err++;
-      dev_kfree_skb(skb);
-      return -EINVAL;
-   }
-   
-   if (!vc->tx)
-   {
-      printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index);
-      vcc->stats->tx_err++;
-      dev_kfree_skb(skb);
-      return -EINVAL;
-   }
-   
-   if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
-   {
-      printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index);
-      vcc->stats->tx_err++;
-      dev_kfree_skb(skb);
-      return -EINVAL;
-   }
-   
-   if (skb->atm.iovcnt != 0)
-   {
-      printk("nicstar%d: No scatter-gather yet.\n", card->index);
-      vcc->stats->tx_err++;
-      dev_kfree_skb(skb);
-      return -EINVAL;
-   }
-   
-   skb->atm.vcc = vcc;
-
-   if (vcc->qos.aal == ATM_AAL5)
-   {
-      buflen = (skb->len + 47 + 8) / 48 * 48;	/* Multiple of 48 */
-      flags = NS_TBD_AAL5;
-      scqe.word_2 = (u32) virt_to_bus(skb->data);
-      scqe.word_3 = (u32) skb->len;
-      scqe.word_4 = ((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
-                    ((u32) vcc->vci) << NS_TBD_VCI_SHIFT;
-      flags |= NS_TBD_EOPDU;
-   }
-   else /* (vcc->qos.aal == ATM_AAL0) */
-   {
-      buflen = ATM_CELL_PAYLOAD;	/* i.e., 48 bytes */
-      flags = NS_TBD_AAL0;
-      scqe.word_2 = (u32) virt_to_bus(skb->data) + NS_AAL0_HEADER;
-      scqe.word_3 = 0x00000000;
-      if (*skb->data & 0x02)	/* Payload type 1 - end of pdu */
-         flags |= NS_TBD_EOPDU;
-      scqe.word_4 = *((u32 *) skb->data) & ~NS_TBD_VC_MASK;
-      /* Force the VPI/VCI to be the same as in VCC struct */
-      scqe.word_4 |= (((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
-                      ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK;
-   }
-
-   if (vcc->qos.txtp.traffic_class == ATM_CBR)
-   {
-      scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen);
-      scq = ((vc_map *) vcc->dev_data)->scq;
-   }
-   else
-   {
-      scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen);
-      scq = card->scq0;
-   }
-
-   if (push_scqe(card, vc, scq, &scqe, skb) != 0)	/* Timeout pushing the TBD */
-   {
-      printk("nicstar%d: Timeout pushing TBD.\n", card->index);
-      vcc->stats->tx_err++;
-      dev_kfree_skb(skb);
-      return -EIO;
-   }
-   vcc->stats->tx++;
-
-   return 0;
-}
-
-
-
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
-                     struct sk_buff *skb)
-{
-   unsigned long flags;
-   ns_scqe tsr;
-   u32 scdi, scqi;
-   int scq_is_vbr;
-   u32 data;
-   int index;
-   
-   if (scq->tail == scq->next)
-   {
-      save_flags(flags); cli();
-      scq->full = 1;
-      current->timeout = jiffies + SCQFULL_TIMEOUT;
-      interruptible_sleep_on(&scq->scqfull_waitq);
-      restore_flags(flags);
-
-      if (scq->full)
-         return 1;
-   }
-   *scq->next = *tbd;
-   index = (int) (scq->next - scq->base);
-   scq->skb[index] = skb;
-   XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n",
-           card->index, (u32) skb, index);
-   XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
-           card->index, tbd->word_1, tbd->word_2, tbd->word_3, tbd->word_4,
-           (u32) scq->next);
-   if (scq->next == scq->last)
-      scq->next = scq->base;
-   else
-      scq->next++;
-
-   vc->tbd_count++;
-   if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
-   {
-      scq->tbd_count++;
-      scq_is_vbr = 1;
-   }
-   else
-      scq_is_vbr = 0;
-
-   if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ)
-   {
-      if (scq->tail == scq->next)
-      {
-         save_flags(flags); cli();
-         scq->full = 1;
-         current->timeout = jiffies + SCQFULL_TIMEOUT;
-         interruptible_sleep_on(&scq->scqfull_waitq);
-         restore_flags(flags);
-      }
-
-      if (!scq->full)
-      {
-         tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
-         if (scq_is_vbr)
-            scdi = NS_TSR_SCDISVBR;
-         else
-            scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
-         scqi = scq->next - scq->base;
-         tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
-         tsr.word_3 = 0x00000000;
-         tsr.word_4 = 0x00000000;
-
-         *scq->next = tsr;
-         index = (int) scqi;
-         scq->skb[index] = NULL;
-         XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
-	         card->index, tsr.word_1, tsr.word_2, tsr.word_3, tsr.word_4,
-		 (u32) scq->next);
-         if (scq->next == scq->last)
-            scq->next = scq->base;
-         else
-            scq->next++;
-         vc->tbd_count = 0;
-         scq->tbd_count = 0;
-      }
-      else
-         PRINTK("nicstar%d: Could not write TSI.\n", card->index);
-   }
-   
-   data = (u32) virt_to_bus(scq->next);
-   ns_write_sram(card, scq->scd, &data, 1);
-   
-   return 0;
-}
-
-
-
-static void process_tsq(ns_dev *card)
-{
-   u32 scdi;
-   scq_info *scq;
-   ns_tsi *previous;
-   
-   if (ns_tsi_isempty(card->tsq.next))
-      return;
-   while (!ns_tsi_isempty(card->tsq.next))
-   {
-      if (!ns_tsi_tmrof(card->tsq.next))
-      {
-         scdi = ns_tsi_getscdindex(card->tsq.next);
-	 if (scdi == NS_TSI_SCDISVBR)
-	    scq = card->scq0;
-	 else
-	 {
-	    if (card->scd2vc[scdi] == NULL)
-	    {
-	       printk("nicstar%d: could not find VC from SCD index.\n",
-	              card->index);
-               ns_tsi_init(card->tsq.next);
-               return;
-            }
-	    scq = card->scd2vc[scdi]->scq;
-         }
-         drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
-         scq->full = 0;
-         wake_up_interruptible(&(scq->scqfull_waitq));
-      }
-
-      ns_tsi_init(card->tsq.next);
-      previous = card->tsq.next;
-      if (card->tsq.next == card->tsq.last)
-         card->tsq.next = card->tsq.base;
-      else
-         card->tsq.next++;
-   }
-   writel((((u32) previous) - ((u32) card->tsq.base)),
-          card->membase + TSQH);
-}
-
-
-
-static void drain_scq(ns_dev *card, scq_info *scq, int pos)
-{
-   struct atm_vcc *vcc;
-   struct sk_buff *skb;
-   int i;
-   
-   XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n",
-           card->index, (u32) scq, pos);
-   if (pos >= scq->num_entries)
-   {
-      printk("nicstar%d: Bad index on drain_scq().\n", card->index);
-      return;
-   }
-
-   i = (int) (scq->tail - scq->base);
-   if (++i == scq->num_entries)
-      i = 0;
-   while (i != pos)
-   {
-      skb = scq->skb[i];
-      XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n",
-              card->index, (u32) skb, i);
-      if (skb != NULL)
-      {
-         vcc = skb->atm.vcc;
-	 if (vcc->pop != NULL)
-	    vcc->pop(vcc, skb);
-	 else
-	    dev_kfree_skb(skb);
-	 scq->skb[i] = NULL;
-      }
-      if (++i == scq->num_entries)
-         i = 0;
-   }
-   scq->tail = scq->base + pos;
-}
-
-
-
-static void process_rsq(ns_dev *card)
-{
-   ns_rsqe *previous;
-
-   if (!ns_rsqe_valid(card->rsq.next))
-      return;
-   while (ns_rsqe_valid(card->rsq.next))
-   {
-      dequeue_rx(card, card->rsq.next);
-      ns_rsqe_init(card->rsq.next);
-      previous = card->rsq.next;
-      if (card->rsq.next == card->rsq.last)
-         card->rsq.next = card->rsq.base;
-      else
-         card->rsq.next++;
-   }
-   writel((((u32) previous) - ((u32) card->rsq.base)),
-          card->membase + RSQH);
-}
-
-
-
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
-{
-   u32 vpi, vci;
-   vc_map *vc;
-   struct sk_buff *iovb;
-   struct iovec *iov;
-   struct atm_vcc *vcc;
-   struct sk_buff *skb;
-   unsigned short aal5_len;
-   int len;
-   u32 stat;
-
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);   
-   card->lbfqc = ns_stat_lfbqc_get(stat);
-
-   skb = (struct sk_buff *) rsqe->buffer_handle;
-   vpi = ns_rsqe_vpi(rsqe);
-   vci = ns_rsqe_vci(rsqe);
-   if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits)
-   {
-      printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n",
-             card->index, vpi, vci);
-      recycle_rx_buf(card, skb);
-      return;
-   }
-   
-   vc = &(card->vcmap[vpi << card->vcibits | vci]);
-   if (!vc->rx)
-   {
-      RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
-             card->index, vpi, vci);
-      recycle_rx_buf(card, skb);
-      return;
-   }
-
-   vcc = vc->rx_vcc;
-
-   if (vcc->qos.aal == ATM_AAL0)
-   {
-      struct sk_buff *sb;
-      unsigned char *cell;
-      int i;
-
-      cell = skb->data;
-      for (i = ns_rsqe_cellcount(rsqe); i; i--)
-      {
-         if ((sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) == NULL)
-         {
-            printk("nicstar%d: Can't allocate buffers for aal0.\n",
-                   card->index);
-            vcc->stats->rx_drop += i;
-            break;
-         }
-         if (!atm_charge(vcc, sb->truesize))
-         {
-            RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",
-                     card->index);
-            vcc->stats->rx_drop += i - 1;	/* already increased by 1 */
-            kfree_skb(sb);
-            break;
-         }
-         /* Rebuild the header */
-         *((u32 *) sb->data) = rsqe->word_1 << 4 |
-                               (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
-         if (i == 1 && ns_rsqe_eopdu(rsqe))
-            *((u32 *) sb->data) |= 0x00000002;
-         skb_put(sb, NS_AAL0_HEADER);
-         memcpy(sb->tail, cell, ATM_CELL_PAYLOAD);
-         skb_put(sb, ATM_CELL_PAYLOAD);
-         sb->atm.vcc = vcc;
-         sb->stamp = xtime;
-         vcc->push(vcc, sb);
-         vcc->stats->rx++;
-         cell += ATM_CELL_PAYLOAD;
-      }
-
-      recycle_rx_buf(card, skb);
-      return;
-   }
-
-   /* To reach this point, the AAL layer can only be AAL5 */
-
-   if ((iovb = vc->rx_iov) == NULL)
-   {
-      iovb = skb_dequeue(&(card->iovpool.queue));
-      if (iovb == NULL)		/* No buffers in the queue */
-      {
-         iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);
-	 if (iovb == NULL)
-	 {
-	    printk("nicstar%d: Out of iovec buffers.\n", card->index);
-            vcc->stats->rx_drop++;
-            recycle_rx_buf(card, skb);
-            return;
-	 }
-      }
-      else
-         if (--card->iovpool.count < card->iovnr.min)
-	 {
-	    struct sk_buff *new_iovb;
-	    if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL)
-	    {
-               skb_queue_tail(&card->iovpool.queue, new_iovb);
-               card->iovpool.count++;
-	    }
-	 }
-      vc->rx_iov = iovb;
-      iovb->atm.iovcnt = 0;
-      iovb->len = 0;
-      iovb->tail = iovb->data = iovb->head;
-      iovb->atm.vcc = vcc;
-      /* IMPORTANT: a pointer to the sk_buff containing the small or large
-                    buffer is stored as iovec base, NOT a pointer to the 
-	            small or large buffer itself. */
-   }
-   else if (iovb->atm.iovcnt >= NS_MAX_IOVECS)
-   {
-      printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
-      vcc->stats->rx_err++;
-      recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
-      iovb->atm.iovcnt = 0;
-      iovb->len = 0;
-      iovb->tail = iovb->data = iovb->head;
-      iovb->atm.vcc = vcc;
-   }
-   iov = &((struct iovec *) iovb->data)[iovb->atm.iovcnt++];
-   iov->iov_base = (void *) skb;
-   iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
-   iovb->len += iov->iov_len;
-
-   if (iovb->atm.iovcnt == 1)
-   {
-      if (skb->list != &card->sbpool.queue)
-      {
-         printk("nicstar%d: Expected a small buffer, and this is not one.\n",
-	        card->index);
-         which_list(card, skb);
-         vcc->stats->rx_err++;
-         recycle_rx_buf(card, skb);
-         vc->rx_iov = NULL;
-         recycle_iov_buf(card, iovb);
-         return;
-      }
-   }
-   else /* iovb->atm.iovcnt >= 2 */
-   {
-      if (skb->list != &card->lbpool.queue)
-      {
-         printk("nicstar%d: Expected a large buffer, and this is not one.\n",
-	        card->index);
-         which_list(card, skb);
-         vcc->stats->rx_err++;
-         recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                       iovb->atm.iovcnt);
-         vc->rx_iov = NULL;
-         recycle_iov_buf(card, iovb);
-	 return;
-      }
-   }
-
-   if (ns_rsqe_eopdu(rsqe))
-   {
-      aal5_len = *((unsigned short *) ((u32) skb->data + iov->iov_len - 6));
-      /* Swap byte order. Is it just me or the nicstar manual sais this should
-         already be in little endian format? */
-      aal5_len = ((aal5_len & 0x00ff) << 8 | (aal5_len & 0xff00) >> 8);
-      len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
-      if (ns_rsqe_crcerr(rsqe) ||
-          len + 8 > iovb->len || len + (47 + 8) < iovb->len)
-      {
-         if (ns_rsqe_crcerr(rsqe))
-	    printk("nicstar%d: AAL5 CRC error.\n", card->index);
-         else
-            printk("nicstar%d: AAL5 PDU size mismatch.\n", card->index);
-         vcc->stats->rx_err++;
-         recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, iovb->atm.iovcnt);
-	 vc->rx_iov = NULL;
-         recycle_iov_buf(card, iovb);
-	 return;
-      }
-
-      /* By this point we (hopefully) have a complete SDU without errors. */
-
-      if (iovb->atm.iovcnt == 1)	/* Just a small buffer */
-      {
-         /* skb points to a small buffer */
-         if (!atm_charge(vcc, skb->truesize))
-         {
-            push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data),
-                        0, 0);
-         }
-         else
-	 {
-            skb_put(skb, len);
-            dequeue_sm_buf(card, skb);
-#ifdef NS_USE_DESTRUCTORS
-            skb->destructor = ns_sb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-            skb->atm.vcc = vcc;
-            skb->stamp = xtime;
-            vcc->push(vcc, skb);
-            vcc->stats->rx++;
-         }
-      }
-      else if (iovb->atm.iovcnt == 2)	/* One small plus one large buffer */
-      {
-         struct sk_buff *sb;
-
-         sb = (struct sk_buff *) (iov - 1)->iov_base;
-         /* skb points to a large buffer */
-
-         if (len <= NS_SMBUFSIZE)
-	 {
-            if (!atm_charge(vcc, sb->truesize))
-            {
-               push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
-                           0, 0);
-            }
-            else
-	    {
-               skb_put(sb, len);
-               dequeue_sm_buf(card, sb);
-#ifdef NS_USE_DESTRUCTORS
-               sb->destructor = ns_sb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-               sb->atm.vcc = vcc;
-               sb->stamp = xtime;
-               vcc->push(vcc, sb);
-               vcc->stats->rx++;
-            }
-
-            push_rxbufs(card, BUF_LG, (u32) skb,
-	                   (u32) virt_to_bus(skb->data), 0, 0);
-
-	 }
-	 else			/* len > NS_SMBUFSIZE, the usual case */
-	 {
-            if (!atm_charge(vcc, skb->truesize))
-            {
-               push_rxbufs(card, BUF_LG, (u32) skb,
-                           (u32) virt_to_bus(skb->data), 0, 0);
-            }
-            else
-            {
-               dequeue_lg_buf(card, skb);
-#ifdef NS_USE_DESTRUCTORS
-               skb->destructor = ns_lb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-               skb_push(skb, NS_SMBUFSIZE);
-               memcpy(skb->data, sb->data, NS_SMBUFSIZE);
-               skb_put(skb, len - NS_SMBUFSIZE);
-               skb->atm.vcc = vcc;
-               skb->stamp = xtime;
-               vcc->push(vcc, skb);
-               vcc->stats->rx++;
-            }
-
-            push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
-                        0, 0);
-
-         }
-	 
-      }
-      else				/* Must push a huge buffer */
-      {
-         struct sk_buff *hb, *sb, *lb;
-	 int remaining, tocopy;
-         int j;
-
-         hb = skb_dequeue(&(card->hbpool.queue));
-         if (hb == NULL)		/* No buffers in the queue */
-         {
-
-            hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC);
-            if (hb == NULL)
-            {
-               printk("nicstar%d: Out of huge buffers.\n", card->index);
-               vcc->stats->rx_drop++;
-               recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                             iovb->atm.iovcnt);
-               vc->rx_iov = NULL;
-               recycle_iov_buf(card, iovb);
-               return;
-            }
-            else if (card->hbpool.count < card->hbnr.min)
-	    {
-               struct sk_buff *new_hb;
-               if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL)
-               {
-                  skb_queue_tail(&card->hbpool.queue, new_hb);
-                  card->hbpool.count++;
-               }
-            }
-	 }
-	 else
-         if (--card->hbpool.count < card->hbnr.min)
-         {
-            struct sk_buff *new_hb;
-            if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL)
-            {
-               skb_queue_tail(&card->hbpool.queue, new_hb);
-               card->hbpool.count++;
-            }
-            if (card->hbpool.count < card->hbnr.min)
-	    {
-               if ((new_hb = alloc_skb(NS_HBUFSIZE, GFP_ATOMIC)) != NULL)
-               {
-                  skb_queue_tail(&card->hbpool.queue, new_hb);
-                  card->hbpool.count++;
-               }
-            }
-         }
-
-         iov = (struct iovec *) iovb->data;
-
-         if (!atm_charge(vcc, hb->truesize))
-	 {
-            recycle_iovec_rx_bufs(card, iov, iovb->atm.iovcnt);
-            if (card->hbpool.count < card->hbnr.max)
-            {
-               skb_queue_tail(&card->hbpool.queue, hb);
-               card->hbpool.count++;
-            }
-	    else
-	       kfree_skb(hb);
-         }
-         else
-	 {
-            /* Copy the small buffer to the huge buffer */
-            sb = (struct sk_buff *) iov->iov_base;
-            memcpy(hb->data, sb->data, iov->iov_len);
-            skb_put(hb, iov->iov_len);
-            remaining = len - iov->iov_len;
-            iov++;
-            /* Free the small buffer */
-            push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data),
-                        0, 0);
-
-            /* Copy all large buffers to the huge buffer and free them */
-            for (j = 1; j < iovb->atm.iovcnt; j++)
-            {
-               lb = (struct sk_buff *) iov->iov_base;
-               tocopy = MIN(remaining, iov->iov_len);
-               memcpy(hb->tail, lb->data, tocopy);
-               skb_put(hb, tocopy);
-               iov++;
-               remaining -= tocopy;
-               push_rxbufs(card, BUF_LG, (u32) lb,
-                           (u32) virt_to_bus(lb->data), 0, 0);
-            }
-#ifdef EXTRA_DEBUG
-            if (remaining != 0 || hb->len != len)
-               printk("nicstar%d: Huge buffer len mismatch.\n", card->index);
-#endif /* EXTRA_DEBUG */
-            hb->atm.vcc = vcc;
-#ifdef NS_USE_DESTRUCTORS
-            hb->destructor = ns_hb_destructor;
-#endif /* NS_USE_DESTRUCTORS */
-            hb->stamp = xtime;
-            vcc->push(vcc, hb);
-            vcc->stats->rx++;
-         }
-      }
-
-      vc->rx_iov = NULL;
-      recycle_iov_buf(card, iovb);
-   }
-
-}
-
-
-
-#ifdef NS_USE_DESTRUCTORS
-
-static void ns_sb_destructor(struct sk_buff *sb)
-{
-   ns_dev *card;
-   u32 stat;
-
-   card = (ns_dev *) sb->atm.vcc->dev->dev_data;
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);   
-   card->lbfqc = ns_stat_lfbqc_get(stat);
-
-   do
-   {
-      sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
-      if (sb == NULL)
-         break;
-      skb_queue_tail(&card->sbpool.queue, sb);
-      skb_reserve(sb, NS_AAL0_HEADER);
-      push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
-   } while (card->sbfqc < card->sbnr.min);
-}
-
-
-
-static void ns_lb_destructor(struct sk_buff *lb)
-{
-   ns_dev *card;
-   u32 stat;
-
-   card = (ns_dev *) lb->atm.vcc->dev->dev_data;
-   stat = readl(card->membase + STAT);
-   card->sbfqc = ns_stat_sfbqc_get(stat);   
-   card->lbfqc = ns_stat_lfbqc_get(stat);
-
-   do
-   {
-      lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
-      if (lb == NULL)
-         break;
-      skb_queue_tail(&card->lbpool.queue, lb);
-      skb_reserve(lb, NS_SMBUFSIZE);
-      push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
-   } while (card->lbfqc < card->lbnr.min);
-}
-
-
-
-static void ns_hb_destructor(struct sk_buff *hb)
-{
-   ns_dev *card;
-
-   card = (ns_dev *) hb->atm.vcc->dev->dev_data;
-
-   while (card->hbpool.count < card->hbnr.init)
-   {
-      hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
-      if (hb == NULL)
-         break;
-      skb_queue_tail(&card->hbpool.queue, hb);
-      card->hbpool.count++;
-   }
-}
-
-#endif /* NS_USE_DESTRUCTORS */
-
-
-
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
-{
-   if (skb->list == &card->sbpool.queue)
-      push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0);
-   else if (skb->list == &card->lbpool.queue)
-      push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data), 0, 0);
-   else
-   {
-      printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
-      kfree_skb(skb);
-   }
-}
-
-
-
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
-{
-   struct sk_buff *skb;
-
-   for (; count > 0; count--)
-   {
-      skb = (struct sk_buff *) (iov++)->iov_base;
-      if (skb->list == &card->sbpool.queue)
-         push_rxbufs(card, BUF_SM, (u32) skb, (u32) virt_to_bus(skb->data),
-	             0, 0);
-      else if (skb->list == &card->lbpool.queue)
-         push_rxbufs(card, BUF_LG, (u32) skb, (u32) virt_to_bus(skb->data),
-	             0, 0);
-      else
-      {
-         printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
-         kfree_skb(skb);
-      }
-   }
-}
-
-
-
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
-{
-   if (card->iovpool.count < card->iovnr.max)
-   {
-      skb_queue_tail(&card->iovpool.queue, iovb);
-      card->iovpool.count++;
-   }
-   else
-      kfree_skb(iovb);
-}
-
-
-
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
-{
-   skb_unlink(sb);
-#ifdef NS_USE_DESTRUCTORS
-   if (card->sbfqc < card->sbnr.min)
-#else
-   if (card->sbfqc < card->sbnr.init)
-   {
-      struct sk_buff *new_sb;
-      if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL)
-      {
-         skb_queue_tail(&card->sbpool.queue, new_sb);
-         skb_reserve(new_sb, NS_AAL0_HEADER);
-         push_rxbufs(card, BUF_SM, (u32) new_sb,
-                     (u32) virt_to_bus(new_sb->data), 0, 0);
-      }
-   }
-   if (card->sbfqc < card->sbnr.init)
-#endif /* NS_USE_DESTRUCTORS */
-   {
-      struct sk_buff *new_sb;
-      if ((new_sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC)) != NULL)
-      {
-         skb_queue_tail(&card->sbpool.queue, new_sb);
-         skb_reserve(new_sb, NS_AAL0_HEADER);
-         push_rxbufs(card, BUF_SM, (u32) new_sb,
-                     (u32) virt_to_bus(new_sb->data), 0, 0);
-      }
-   }
-}
-
-
-
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb)
-{
-   skb_unlink(lb);
-#ifdef NS_USE_DESTRUCTORS
-   if (card->lbfqc < card->lbnr.min)
-#else
-   if (card->lbfqc < card->lbnr.init)
-   {
-      struct sk_buff *new_lb;
-      if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL)
-      {
-         skb_queue_tail(&card->lbpool.queue, new_lb);
-         skb_reserve(new_lb, NS_SMBUFSIZE);
-         push_rxbufs(card, BUF_LG, (u32) new_lb,
-                     (u32) virt_to_bus(new_lb->data), 0, 0);
-      }
-   }
-   if (card->lbfqc < card->lbnr.init)
-#endif /* NS_USE_DESTRUCTORS */
-   {
-      struct sk_buff *new_lb;
-      if ((new_lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC)) != NULL)
-      {
-         skb_queue_tail(&card->lbpool.queue, new_lb);
-         skb_reserve(new_lb, NS_SMBUFSIZE);
-         push_rxbufs(card, BUF_LG, (u32) new_lb,
-                     (u32) virt_to_bus(new_lb->data), 0, 0);
-      }
-   }
-}
-
-
-
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
-{
-   u32 stat;
-   ns_dev *card;
-   int left;
-
-   left = (int) *pos;
-   card = (ns_dev *) dev->dev_data;
-   stat = readl(card->membase + STAT);
-   if (!left--)
-      return sprintf(page, "Pool   count    min   init    max \n");
-   if (!left--)
-      return sprintf(page, "Small  %5d  %5d  %5d  %5d \n",
-                     ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init,
-		     card->sbnr.max);
-   if (!left--)
-      return sprintf(page, "Large  %5d  %5d  %5d  %5d \n",
-                     ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init,
-		     card->lbnr.max);
-   if (!left--)
-      return sprintf(page, "Huge   %5d  %5d  %5d  %5d \n", card->hbpool.count,
-                     card->hbnr.min, card->hbnr.init, card->hbnr.max);
-   if (!left--)
-      return sprintf(page, "Iovec  %5d  %5d  %5d  %5d \n", card->iovpool.count,
-                     card->iovnr.min, card->iovnr.init, card->iovnr.max);
-   if (!left--)
-   {
-      int retval;
-      retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt);
-      card->intcnt = 0;
-      return retval;
-   }
-   /* Dump 25.6 Mbps PHY registers */
-   if (card->max_pcr == IDT_25_PCR && !left--)
-   {
-      u32 phy_regs[4];
-      u32 i;
-
-      for (i = 0; i < 4; i++)
-      {
-         while (CMD_BUSY(card));
-         writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD);
-         while (CMD_BUSY(card));
-         phy_regs[i] = readl(card->membase + DR0) & 0x000000FF;
-      }
-
-      return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n",
-                     phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]);
-   }
-#if 0
-   /* Dump TST */
-   if (left-- < NS_TST_NUM_ENTRIES)
-   {
-      if (card->tste2vc[left + 1] == NULL)
-         return sprintf(page, "%5d - VBR/UBR \n", left + 1);
-      else
-         return sprintf(page, "%5d - %d %d \n", left + 1,
-                        card->tste2vc[left + 1]->tx_vcc->vpi,
-                        card->tste2vc[left + 1]->tx_vcc->vci);
-   }
-#endif /* 0 */
-   return 0;
-}
-
-
-
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg)
-{
-   ns_dev *card;
-   pool_levels pl;
-   int btype;
-   unsigned long flags;
-
-   card = dev->dev_data;
-   switch (cmd)
-   {
-      case NS_GETPSTAT:
-         if (get_user(pl.buftype, &((pool_levels *) arg)->buftype))
-	    return -EFAULT;
-         switch (pl.buftype)
-	 {
-	    case NS_BUFTYPE_SMALL:
-	       pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT));
-	       pl.level.min = card->sbnr.min;
-	       pl.level.init = card->sbnr.init;
-	       pl.level.max = card->sbnr.max;
-	       break;
-
-	    case NS_BUFTYPE_LARGE:
-	       pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT));
-	       pl.level.min = card->lbnr.min;
-	       pl.level.init = card->lbnr.init;
-	       pl.level.max = card->lbnr.max;
-	       break;
-
-	    case NS_BUFTYPE_HUGE:
-	       pl.count = card->hbpool.count;
-	       pl.level.min = card->hbnr.min;
-	       pl.level.init = card->hbnr.init;
-	       pl.level.max = card->hbnr.max;
-	       break;
-
-	    case NS_BUFTYPE_IOVEC:
-	       pl.count = card->iovpool.count;
-	       pl.level.min = card->iovnr.min;
-	       pl.level.init = card->iovnr.init;
-	       pl.level.max = card->iovnr.max;
-	       break;
-
-            default:
-	       return -EINVAL;
-
-	 }
-         if (!copy_to_user((pool_levels *) arg, &pl, sizeof(pl)))
-	    return (sizeof(pl));
-	 else
-	    return -EFAULT;
-
-      case NS_SETBUFLEV:
-         if (!suser())
-	    return -EPERM;
-         if (copy_from_user(&pl, (pool_levels *) arg, sizeof(pl)))
-	    return -EFAULT;
-	 if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max)
-	    return -EINVAL;
-	 if (pl.level.min == 0)
-	    return -EINVAL;
-         switch (pl.buftype)
-	 {
-	    case NS_BUFTYPE_SMALL:
-               if (pl.level.max > TOP_SB)
-	          return -EINVAL;
-	       card->sbnr.min = pl.level.min;
-	       card->sbnr.init = pl.level.init;
-	       card->sbnr.max = pl.level.max;
-	       break;
-
-	    case NS_BUFTYPE_LARGE:
-               if (pl.level.max > TOP_LB)
-	          return -EINVAL;
-	       card->lbnr.min = pl.level.min;
-	       card->lbnr.init = pl.level.init;
-	       card->lbnr.max = pl.level.max;
-	       break;
-
-	    case NS_BUFTYPE_HUGE:
-               if (pl.level.max > TOP_HB)
-	          return -EINVAL;
-	       card->hbnr.min = pl.level.min;
-	       card->hbnr.init = pl.level.init;
-	       card->hbnr.max = pl.level.max;
-	       break;
-
-	    case NS_BUFTYPE_IOVEC:
-               if (pl.level.max > TOP_IOVB)
-	          return -EINVAL;
-	       card->iovnr.min = pl.level.min;
-	       card->iovnr.init = pl.level.init;
-	       card->iovnr.max = pl.level.max;
-	       break;
-
-            default:
-	       return -EINVAL;
-
-         }	 
-         return 0;
-
-      case NS_ADJBUFLEV:
-         if (!suser())
-	    return -EPERM;
-         btype = (int) arg;	/* an int is the same size as a pointer */
-         switch (btype)
-	 {
-	    case NS_BUFTYPE_SMALL:
-	       while (card->sbfqc < card->sbnr.init)
-	       {
-                  struct sk_buff *sb;
-
-                  sb = alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
-                  if (sb == NULL)
-                     return -ENOMEM;
-                  skb_queue_tail(&card->sbpool.queue, sb);
-                  skb_reserve(sb, NS_AAL0_HEADER);
-                  push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0);
-	       }
-	       break;
-
-            case NS_BUFTYPE_LARGE:
-	       while (card->lbfqc < card->lbnr.init)
-	       {
-                  struct sk_buff *lb;
-
-                  lb = alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
-                  if (lb == NULL)
-                     return -ENOMEM;
-                  skb_queue_tail(&card->lbpool.queue, lb);
-                  skb_reserve(lb, NS_SMBUFSIZE);
-                  push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0);
-	       }
-	       break;
-
-            case NS_BUFTYPE_HUGE:
-               while (card->hbpool.count > card->hbnr.init)
-	       {
-                  struct sk_buff *hb;
-
-                  save_flags(flags); cli();
-		  hb = skb_dequeue(&card->hbpool.queue);
-		  card->hbpool.count--;
-		  restore_flags(flags);
-                  if (hb == NULL)
-		     printk("nicstar%d: huge buffer count inconsistent.\n",
-		            card->index);
-                  else
-		     kfree_skb(hb);
-		  
-	       }
-               while (card->hbpool.count < card->hbnr.init)
-               {
-                  struct sk_buff *hb;
-
-                  hb = alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
-                  if (hb == NULL)
-                     return -ENOMEM;
-                  save_flags(flags); cli();
-                  skb_queue_tail(&card->hbpool.queue, hb);
-                  card->hbpool.count++;
-		  restore_flags(flags);
-               }
-	       break;
-
-            case NS_BUFTYPE_IOVEC:
-	       while (card->iovpool.count > card->iovnr.init)
-	       {
-	          struct sk_buff *iovb;
-
-                  save_flags(flags); cli();
-		  iovb = skb_dequeue(&card->iovpool.queue);
-		  card->iovpool.count--;
-		  restore_flags(flags);
-                  if (iovb == NULL)
-		     printk("nicstar%d: iovec buffer count inconsistent.\n",
-		            card->index);
-                  else
-		     kfree_skb(iovb);
-
-	       }
-               while (card->iovpool.count < card->iovnr.init)
-	       {
-	          struct sk_buff *iovb;
-
-                  iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
-                  if (iovb == NULL)
-                     return -ENOMEM;
-                  save_flags(flags); cli();
-                  skb_queue_tail(&card->iovpool.queue, iovb);
-                  card->iovpool.count++;
-		  restore_flags(flags);
-	       }
-	       break;
-
-            default:
-	       return -EINVAL;
-
-	 }
-         return 0;
-
-      default:
-         if (dev->phy->ioctl == NULL) return -EINVAL;
-	 return dev->phy->ioctl(dev, cmd, arg);
-   }
-}
-
-
-
-static void which_list(ns_dev *card, struct sk_buff *skb)
-{
-   printk("It's a %s buffer.\n", skb->list == &card->sbpool.queue ?
-          "small" : skb->list == &card->lbpool.queue ? "large" :
-	  skb->list == &card->hbpool.queue ? "huge" :
-	  skb->list == &card->iovpool.queue ? "iovec" : "unknown");
-}
-
-
-
-static void ns_poll(unsigned long arg)
-{
-   int i;
-   ns_dev *card;
-   unsigned long flags;
-   u32 stat_r, stat_w;
-
-   PRINTK("nicstar: Entering ns_poll().\n");
-   for (i = 0; i < num_cards; i++)
-   {
-      card = cards[i];
-      save_flags(flags); cli();
-      if (card->in_poll)
-      {
-         printk("nicstar: Re-entering ns_poll()???\n");
-         continue;
-      }
-      card->in_poll = 1;
-      if (card->in_handler)
-      {
-         card->in_poll = 0;
-         printk("nicstar%d: ns_poll called while in interrupt handler!?\n",
-                card->index);
-         continue;
-      }
-
-      stat_w = 0;
-      stat_r = readl(card->membase + STAT);
-      if (stat_r & NS_STAT_TSIF)
-         stat_w |= NS_STAT_TSIF;
-      if (stat_r & NS_STAT_EOPDU)
-         stat_w |= NS_STAT_EOPDU;
-
-      process_tsq(card);
-      process_rsq(card);
-
-      writel(card->membase + STAT, stat_w);
-      card->in_poll = 0;
-      restore_flags(flags);
-   }
-   mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD);
-   PRINTK("nicstar: Leaving ns_poll().\n");
-}
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/suni.c linux/drivers/atm/suni.c
--- v2.3.17/linux/drivers/atm/suni.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/atm/suni.c	Wed Sep  8 11:14:32 1999
@@ -1,6 +1,6 @@
 /* drivers/atm/suni.c - PMC SUNI (PHY) driver */
  
-/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
 
 
 #include <linux/module.h>
@@ -45,7 +45,7 @@
   PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg)
 
 
-static struct timer_list poll_timer = { NULL, NULL, 0L, 0L, NULL };
+static struct timer_list poll_timer;
 static int start_timer = 1;
 static struct suni_priv *sunis = NULL;
 
@@ -91,11 +91,7 @@
 		    ((GET(TACP_TCCM) & 7) << 16);
 		if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX;
 	}
-	if (!start_timer) {
-		del_timer(&poll_timer);
-		poll_timer.expires = jiffies+HZ;
-		add_timer(&poll_timer);
-	}
+	if (!start_timer) mod_timer(&poll_timer,jiffies+HZ);
 }
 
 
@@ -244,7 +240,7 @@
 	else {
 		start_timer = 0;
 		restore_flags(flags);
-		/*init_timer(&poll_timer);*/
+		init_timer(&poll_timer);
 		poll_timer.expires = jiffies+HZ;
 		poll_timer.function = suni_hz;
 #if 0
@@ -282,9 +278,10 @@
 }
 
 
-#ifdef MODULE
-
 EXPORT_SYMBOL(suni_init);
+
+
+#ifdef MODULE
 
 
 int init_module(void)
diff -u --recursive --new-file v2.3.17/linux/drivers/atm/zatm.c linux/drivers/atm/zatm.c
--- v2.3.17/linux/drivers/atm/zatm.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/atm/zatm.c	Wed Sep  8 11:14:32 1999
@@ -347,7 +347,7 @@
 
 #ifdef CONFIG_ATM_ZATM_EXACT_TS
 
-static struct timer_list sync_timer = { NULL, NULL, 0L, 0L, NULL };
+static struct timer_list sync_timer;
 
 
 /*
@@ -454,9 +454,7 @@
 		zatm_dev->last_real_time = now;
 		zatm_dev->last_clk = ticks;
 	}
-	del_timer(&sync_timer);
-	sync_timer.expires += POLL_INTERVAL*HZ;
-	add_timer(&sync_timer);
+	mod_timer(&sync_timer,sync_timer.expires+POLL_INTERVAL*HZ);
 }
 
 
@@ -475,6 +473,7 @@
 	zatm_dev->last_clk = zpeekl(zatm_dev,uPD98401_TSR);
 	if (start_timer) {
 		start_timer = 0;
+		init_timer(&sync_timer);
 		sync_timer.expires = jiffies+POLL_INTERVAL*HZ;
 		sync_timer.function = zatm_clock_sync;
 		add_timer(&sync_timer);
diff -u --recursive --new-file v2.3.17/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.3.17/linux/drivers/block/DAC960.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/DAC960.c	Wed Sep  8 11:51:21 1999
@@ -41,7 +41,7 @@
 #include <linux/pci.h>
 #include <asm/io.h>
 #include <asm/segment.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include "DAC960.h"
 
diff -u --recursive --new-file v2.3.17/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.3.17/linux/drivers/block/cpqarray.c	Thu Aug  5 15:04:42 1999
+++ linux/drivers/block/cpqarray.c	Wed Sep  8 11:51:22 1999
@@ -35,8 +35,8 @@
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
 #include <linux/hdreg.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
 #include <asm/io.h>
 
 
diff -u --recursive --new-file v2.3.17/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.17/linux/drivers/block/ll_rw_blk.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/block/ll_rw_blk.c	Wed Sep  8 10:59:07 1999
@@ -830,7 +830,7 @@
 #ifdef CONFIG_BLK_DEV_FD
 	floppy_init();
 #else
-#if !defined (__mc68000__) && !defined(CONFIG_PMAC) && !defined(__sparc__)\
+#if !defined (__mc68000__) && !defined(CONFIG_PPC) && !defined(__sparc__)\
     && !defined(CONFIG_APUS) && !defined(__sh__)
 	outb_p(0xc, 0x3f2);
 #endif
diff -u --recursive --new-file v2.3.17/linux/drivers/block/paride/paride.c linux/drivers/block/paride/paride.c
--- v2.3.17/linux/drivers/block/paride/paride.c	Wed May 26 09:30:31 1999
+++ linux/drivers/block/paride/paride.c	Wed Sep  8 11:59:00 1999
@@ -24,7 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/string.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #ifdef CONFIG_PARPORT_MODULE
 #define CONFIG_PARPORT
diff -u --recursive --new-file v2.3.17/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c
--- v2.3.17/linux/drivers/block/paride/pcd.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/paride/pcd.c	Wed Sep  8 11:59:00 1999
@@ -142,9 +142,9 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/cdrom.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
 
 #ifndef MODULE
 
diff -u --recursive --new-file v2.3.17/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.3.17/linux/drivers/block/paride/pd.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/paride/pd.c	Wed Sep  8 11:59:00 1999
@@ -161,8 +161,8 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/cdrom.h>	/* for the eject ioctl */
+#include <linux/spinlock.h>
 
-#include <asm/spinlock.h>
 #include <asm/uaccess.h>
 
 #ifndef MODULE
diff -u --recursive --new-file v2.3.17/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c
--- v2.3.17/linux/drivers/block/paride/pf.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/paride/pf.c	Wed Sep  8 11:59:00 1999
@@ -160,7 +160,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/cdrom.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.17/linux/drivers/char/Config.in	Tue Sep  7 12:14:06 1999
+++ linux/drivers/char/Config.in	Tue Sep  7 14:51:28 1999
@@ -210,4 +210,11 @@
 fi
 endmenu
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
+  if [ "$CONFIG_DRM" = "y" ]; then
+    dep_tristate '   3dlabs GMX 2000' CONFIG_DRM_GAMMA m
+  fi
+fi
+
 endmenu
diff -u --recursive --new-file v2.3.17/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.3.17/linux/drivers/char/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/Makefile	Tue Sep  7 14:51:28 1999
@@ -566,6 +566,11 @@
   endif
 endif
 
+ifeq ($(CONFIG_DRM),y)
+  ALL_SUB_DIRS += drm
+  MOD_SUB_DIRS += drm
+endif
+
 include $(TOPDIR)/Rules.make
 
 fastdep:
diff -u --recursive --new-file v2.3.17/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.3.17/linux/drivers/char/adbmouse.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/adbmouse.c	Wed Sep  8 10:59:07 1999
@@ -174,16 +174,22 @@
  * option, which is about using ADB keyboard buttons to emulate
  * mouse buttons. -- paulus
  */
-void __init adb_mouse_setup(char *str, int *ints)
+static int __init adb_mouse_setup(char *str)
 {
+	int ints[4];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
 	if (ints[0] >= 1) {
-		adb_emulate_buttons = ints[1] > 0;
-		if (ints[1] > 1)
-			adb_button2_keycode = ints[1];
+		adb_emulate_buttons = ints[1];
 		if (ints[0] >= 2)
-			adb_button3_keycode = ints[2];
+			adb_button2_keycode = ints[2];
+		if (ints[0] >= 3)
+			adb_button3_keycode = ints[3];
 	}
+	return 1;
 }
+
+__setup("adb_buttons=", adb_mouse_setup);
 
 #ifdef MODULE
 int init_module(void)
diff -u --recursive --new-file v2.3.17/linux/drivers/char/buz.c linux/drivers/char/buz.c
--- v2.3.17/linux/drivers/char/buz.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/buz.c	Wed Sep  8 11:51:22 1999
@@ -47,7 +47,7 @@
 #include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include <linux/videodev.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.3.17/linux/drivers/char/cyclades.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/cyclades.c	Wed Sep  8 11:51:22 1999
@@ -619,14 +619,13 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
-
-#include <asm/spinlock.h>
 
 #define	CY_LOCK(info,flags)					\
 		do {						\
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/Makefile linux/drivers/char/drm/Makefile
--- v2.3.17/linux/drivers/char/drm/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/Makefile	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,27 @@
+#
+# Makefile for the drm device driver.  This driver provides support for
+# the Direct Rendering Infrastructure (DRI) in XFree86 4.x.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+L_TARGET        := libdrm.a
+
+L_OBJS		:= init.o memory.o proc.o auth.o context.o drawable.o bufs.o \
+			lists.o lock.o ioctl.o fops.o vm.o dma.o
+
+M_OBJS		:= 
+
+ifdef CONFIG_DRM_GAMMA
+M_OBJS          += gamma.o
+endif
+
+include $(TOPDIR)/Rules.make
+
+gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET)
+	$(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o -L. -ldrm
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/README.drm linux/drivers/char/drm/README.drm
--- v2.3.17/linux/drivers/char/drm/README.drm	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/README.drm	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,39 @@
+
+The Direct Rendering Manager (drm) is a device-independent kernel-level
+device driver that provides support for the XFree86 Direct Rendering
+Infrastructure (DRI).
+
+The DRM supports the Direct Rendering Infrastructure (DRI) in four major
+ways:
+
+    1. The DRM provides synchronized access to the graphics hardware via
+       the use of an optimized two-tiered lock.
+
+    2. The DRM enforces the DRI security policy for access to the graphics
+       hardware by only allowing authenticated X11 clients access to
+       restricted regions of memory.
+
+    3. The DRM provides a generic DMA engine, complete with multiple
+       queues and the ability to detect the need for an OpenGL context
+       switch.
+
+    4. The DRM is extensible via the use of small device-specific modules
+       that rely extensively on the API exported by the DRM module.
+
+
+Documentation on the DRI is available from:
+    http://precisioninsight.com/piinsights.html
+
+For specific information about kernel-level support, see:
+
+    The Direct Rendering Manager, Kernel Support for the Direct Rendering
+    Infrastructure
+    http://precisioninsight.com/dr/drm.html
+
+    Hardware Locking for the Direct Rendering Infrastructure
+    http://precisioninsight.com/dr/locking.html
+
+    A Security Analysis of the Direct Rendering Infrastructure
+    http://precisioninsight.com/dr/security.html
+
+
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/auth.c linux/drivers/char/drm/auth.c
--- v2.3.17/linux/drivers/char/drm/auth.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/auth.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,161 @@
+/* auth.c -- IOCTLs for authentication -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/auth.c,v 1.4 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_hash_magic(drm_magic_t magic)
+{
+	return magic & (DRM_HASH_SIZE-1);
+}
+
+static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic)
+{
+	drm_file_t	  *retval = NULL;
+	drm_magic_entry_t *pt;
+	int		  hash	  = drm_hash_magic(magic);
+
+	down(&dev->struct_sem);
+	for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+		if (pt->priv->authenticated) continue;
+		if (pt->magic == magic) {
+			retval = pt->priv;
+			break;
+		}
+	}
+	up(&dev->struct_sem);
+	return retval;
+}
+
+int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+{
+	int		  hash;
+	drm_magic_entry_t *entry;
+	
+	DRM_DEBUG("%d\n", magic);
+	
+	hash	     = drm_hash_magic(magic);
+	entry	     = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
+	if (!entry) return -ENOMEM;
+	entry->magic = magic;
+	entry->priv  = priv;
+	entry->next  = NULL;
+
+	down(&dev->struct_sem);
+	if (dev->magiclist[hash].tail) {
+		dev->magiclist[hash].tail->next = entry;
+		dev->magiclist[hash].tail	= entry;
+	} else {
+		dev->magiclist[hash].head	= entry;
+		dev->magiclist[hash].tail	= entry;
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
+{
+	drm_magic_entry_t *prev = NULL;
+	drm_magic_entry_t *pt;
+	int		  hash;
+	
+	DRM_DEBUG("%d\n", magic);
+	hash = drm_hash_magic(magic);
+	
+	down(&dev->struct_sem);
+	for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+		if (pt->magic == magic) {
+			if (dev->magiclist[hash].head == pt) {
+				dev->magiclist[hash].head = pt->next;
+			}
+			if (dev->magiclist[hash].tail == pt) {
+				dev->magiclist[hash].tail = prev;
+			}
+			if (prev) {
+				prev->next = pt->next;
+			}
+			up(&dev->struct_sem);
+			return 0;
+		}
+	}
+	up(&dev->struct_sem);
+
+	drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+	
+	return -EINVAL;
+}
+
+int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	static drm_magic_t sequence = 0;
+	static spinlock_t  lock	    = SPIN_LOCK_UNLOCKED;
+	drm_file_t	   *priv    = filp->private_data;
+	drm_device_t	   *dev	    = priv->dev;
+	drm_auth_t	   auth;
+
+				/* Find unique magic */
+	if (priv->magic) {
+		auth.magic = priv->magic;
+	} else {
+		spin_lock(&lock);
+		do {
+			if (!sequence) ++sequence; /* reserve 0 */
+			auth.magic = sequence++;
+		} while (drm_find_file(dev, auth.magic));
+		spin_unlock(&lock);
+		priv->magic = auth.magic;
+		drm_add_magic(dev, priv, auth.magic);
+	}
+	
+	DRM_DEBUG("%u\n", auth.magic);
+	copy_to_user_ret((drm_auth_t *)arg, &auth, sizeof(auth), -EFAULT);
+	return 0;
+}
+
+int drm_authmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	   *priv    = filp->private_data;
+	drm_device_t	   *dev	    = priv->dev;
+	drm_auth_t	   auth;
+	drm_file_t	   *file;
+
+	copy_from_user_ret(&auth, (drm_auth_t *)arg, sizeof(auth), -EFAULT);
+	DRM_DEBUG("%u\n", auth.magic);
+	if ((file = drm_find_file(dev, auth.magic))) {
+		file->authenticated = 1;
+		drm_remove_magic(dev, auth.magic);
+		return 0;
+	}
+	return -EINVAL;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/bufs.c linux/drivers/char/drm/bufs.c
--- v2.3.17/linux/drivers/char/drm/bufs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/bufs.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,527 @@
+/* bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:10 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/bufs.c,v 1.8 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "linux/un.h"
+
+				/* Compute order.  Can be made faster. */
+int drm_order(unsigned long size)
+{
+	int	      order;
+	unsigned long tmp;
+
+	for (order = 0, tmp = size; tmp >>= 1; ++order);
+	if (size & ~(1 << order)) ++order;
+	return order;
+}
+
+int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_map_t	*map;
+	
+	if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */
+
+	map	     = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+	if (!map) return -ENOMEM;
+	if (copy_from_user(map, (drm_map_t *)arg, sizeof(*map))) {
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EFAULT;
+	}
+
+	DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
+		  map->offset, map->size, map->type);
+	if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EINVAL;
+	}
+	map->mtrr   = -1;
+	map->handle = 0;
+
+	switch (map->type) {
+	case _DRM_REGISTERS:
+	case _DRM_FRAME_BUFFER:	
+		if (map->offset + map->size < map->offset
+		    || map->offset < virt_to_phys(high_memory)) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -EINVAL;
+		}
+#ifdef CONFIG_MTRR
+		if (map->type == _DRM_FRAME_BUFFER
+		    || (map->flags & _DRM_WRITE_COMBINING)) {
+			map->mtrr = mtrr_add(map->offset, map->size,
+					     MTRR_TYPE_WRCOMB, 1);
+		}
+#endif
+		map->handle = drm_ioremap(map->offset, map->size);
+		break;
+			
+
+	case _DRM_SHM:
+		DRM_DEBUG("%ld %d\n", map->size, drm_order(map->size));
+		map->handle = (void *)drm_alloc_pages(drm_order(map->size)
+						      - PAGE_SHIFT,
+						      DRM_MEM_SAREA);
+		if (!map->handle) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -ENOMEM;
+		}
+		map->offset = (unsigned long)map->handle;
+		if (map->flags & _DRM_CONTAINS_LOCK) {
+			dev->lock.hw_lock = map->handle; /* Pointer to lock */
+		}
+		break;
+	default:
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EINVAL;
+	}
+
+	down(&dev->struct_sem);
+	if (dev->maplist) {
+		++dev->map_count;
+		dev->maplist = drm_realloc(dev->maplist,
+					   (dev->map_count-1)
+					   * sizeof(*dev->maplist),
+					   dev->map_count
+					   * sizeof(*dev->maplist),
+					   DRM_MEM_MAPS);
+	} else {
+		dev->map_count = 1;
+		dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist),
+					 DRM_MEM_MAPS);
+	}
+	dev->maplist[dev->map_count-1] = map;
+	up(&dev->struct_sem);
+
+	copy_to_user_ret((drm_map_t *)arg, map, sizeof(*map), -EFAULT);
+	if (map->type != _DRM_SHM) {
+		copy_to_user_ret(&((drm_map_t *)arg)->handle,
+				 &map->offset,
+				 sizeof(map->offset),
+				 -EFAULT);
+	}		
+	return 0;
+}
+
+int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 count;
+	int		 order;
+	int		 size;
+	int		 total;
+	int		 page_order;
+	drm_buf_entry_t	 *entry;
+	unsigned long	 page;
+	drm_buf_t	 *buf;
+	int		 alignment;
+	unsigned long	 offset;
+	int		 i;
+	int		 byte_count;
+	int		 page_count;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	count	   = request.count;
+	order	   = drm_order(request.size);
+	size	   = 1 << order;
+	
+	DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n",
+		  request.count, request.size, size, order, dev->queue_count);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+
+	alignment  = (request.flags & DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total	   = PAGE_SIZE << page_order;
+
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+	
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;	/* May only call once for each order */
+	}
+	
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+	entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
+				   DRM_MEM_SEGS);
+	if (!entry->seglist) {
+		drm_free(entry->buflist,
+			 count * sizeof(*entry->buflist),
+			 DRM_MEM_BUFS);
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->seglist, 0, count * sizeof(*entry->seglist));
+
+	dma->pagelist = drm_realloc(dma->pagelist,
+				    dma->page_count * sizeof(*dma->pagelist),
+				    (dma->page_count + (count << page_order))
+				    * sizeof(*dma->pagelist),
+				    DRM_MEM_PAGES);
+	DRM_DEBUG("pagelist: %d entries\n",
+		  dma->page_count + (count << page_order));
+
+
+	entry->buf_size	  = size;
+	entry->page_order = page_order;
+	byte_count	  = 0;
+	page_count	  = 0;
+	while (entry->buf_count < count) {
+		if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
+		entry->seglist[entry->seg_count++] = page;
+		for (i = 0; i < (1 << page_order); i++) {
+			DRM_DEBUG("page %d @ 0x%08lx\n",
+				  dma->page_count + page_count,
+				  page + PAGE_SIZE * i);
+			dma->pagelist[dma->page_count + page_count++]
+				= page + PAGE_SIZE * i;
+		}
+		for (offset = 0;
+		     offset + size <= total && entry->buf_count < count;
+		     offset += alignment, ++entry->buf_count) {
+			buf	     = &entry->buflist[entry->buf_count];
+			buf->idx     = dma->buf_count + entry->buf_count;
+			buf->total   = alignment;
+			buf->order   = order;
+			buf->used    = 0;
+			buf->offset  = (dma->byte_count + byte_count + offset);
+			buf->address = (void *)(page + offset);
+			buf->next    = NULL;
+			buf->waiting = 0;
+			buf->pending = 0;
+			init_waitqueue_head(&buf->dma_wait);
+			buf->pid     = 0;
+#if DRM_DMA_HISTOGRAM
+			buf->time_queued     = 0;
+			buf->time_dispatched = 0;
+			buf->time_completed  = 0;
+			buf->time_freed	     = 0;
+#endif
+			DRM_DEBUG("buffer %d @ %p\n",
+				  entry->buf_count, buf->address);
+		}
+		byte_count += PAGE_SIZE << page_order;
+	}
+
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+	dma->buf_count	+= entry->buf_count;
+	dma->seg_count	+= entry->seg_count;
+	dma->page_count += entry->seg_count << page_order;
+	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+	
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+	
+	up(&dev->struct_sem);
+
+	request.count = entry->buf_count;
+	request.size  = size;
+
+	copy_to_user_ret((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+	
+	atomic_dec(&dev->buf_alloc);
+	return 0;
+}
+
+int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_info_t	 request;
+	int		 i;
+	int		 count;
+
+	if (!dma) return -EINVAL;
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_info_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+		if (dma->bufs[i].buf_count) ++count;
+	}
+	
+	DRM_DEBUG("count = %d\n", count);
+	
+	if (request.count >= count) {
+		for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+			if (dma->bufs[i].buf_count) {
+				copy_to_user_ret(&request.list[count].count,
+						 &dma->bufs[i].buf_count,
+						 sizeof(dma->bufs[0]
+							.buf_count),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].size,
+						 &dma->bufs[i].buf_size,
+						 sizeof(dma->bufs[0].buf_size),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].low_mark,
+						 &dma->bufs[i]
+						 .freelist.low_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.low_mark),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count]
+						 .high_mark,
+						 &dma->bufs[i]
+						 .freelist.high_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.high_mark),
+						 -EFAULT);
+				DRM_DEBUG("%d %d %d %d %d\n",
+					  i,
+					  dma->bufs[i].buf_count,
+					  dma->bufs[i].buf_size,
+					  dma->bufs[i].freelist.low_mark,
+					  dma->bufs[i].freelist.high_mark);
+				++count;
+			}
+		}
+	}
+	request.count = count;
+
+	copy_to_user_ret((drm_buf_info_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+	
+	return 0;
+}
+
+int drm_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 order;
+	drm_buf_entry_t	 *entry;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d, %d, %d\n",
+		  request.size, request.low_mark, request.high_mark);
+	order = drm_order(request.size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	entry = &dma->bufs[order];
+
+	if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+		return -EINVAL;
+	if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+		return -EINVAL;
+
+	entry->freelist.low_mark  = request.low_mark;
+	entry->freelist.high_mark = request.high_mark;
+	
+	return 0;
+}
+
+int drm_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_free_t	 request;
+	int		 i;
+	int		 idx;
+	drm_buf_t	 *buf;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_free_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d\n", request.count);
+	for (i = 0; i < request.count; i++) {
+		copy_from_user_ret(&idx,
+				   &request.list[i],
+				   sizeof(idx),
+				   -EFAULT);
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d freeing buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	
+	return 0;
+}
+
+int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	int		 retcode = 0;
+	const int	 zero	 = 0;
+	unsigned long	 virtual;
+	unsigned long	 address;
+	drm_buf_map_t	 request;
+	int		 i;
+
+	if (!dma) return -EINVAL;
+	
+	DRM_DEBUG("\n");
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_map_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	if (request.count >= dma->buf_count) {
+		virtual = do_mmap(filp, 0, dma->byte_count,
+				  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+		if (virtual > -1024UL) {
+				/* Real error */
+			retcode = (signed long)virtual;
+			goto done;
+		}
+		request.virtual = (void *)virtual;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			if (copy_to_user(&request.list[i].idx,
+					 &dma->buflist[i]->idx,
+					 sizeof(request.list[0].idx))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].total,
+					 &dma->buflist[i]->total,
+					 sizeof(request.list[0].total))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].used,
+					 &zero,
+					 sizeof(zero))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			address = virtual + dma->buflist[i]->offset;
+			if (copy_to_user(&request.list[i].address,
+					 &address,
+					 sizeof(address))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+		}
+	}
+done:
+	request.count = dma->buf_count;
+	DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+
+	copy_to_user_ret((drm_buf_map_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+
+	return retcode;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/context.c linux/drivers/char/drm/context.c
--- v2.3.17/linux/drivers/char/drm/context.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/context.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,308 @@
+/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:32:09 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/context.c,v 1.5 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gen_ioctl.c,v 1.2 1999/06/27 14:08:27 dawes Exp $
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
+{
+	DRM_DEBUG("\n");
+	
+	if (atomic_read(&q->use_count) != 1
+	    || atomic_read(&q->finalization)
+	    || atomic_read(&q->block_count)) {
+		DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
+			  atomic_read(&q->use_count),
+			  atomic_read(&q->finalization),
+			  atomic_read(&q->block_count));
+	}
+		  
+	atomic_set(&q->finalization,  0);
+	atomic_set(&q->block_count,   0);
+	atomic_set(&q->block_read,    0);
+	atomic_set(&q->block_write,   0);
+	atomic_set(&q->total_queued,  0);
+	atomic_set(&q->total_flushed, 0);
+	atomic_set(&q->total_locks,   0);
+
+	init_waitqueue_head(&q->write_queue);
+	init_waitqueue_head(&q->read_queue);
+	init_waitqueue_head(&q->flush_queue);
+
+	q->flags = ctx->flags;
+
+	drm_waitlist_create(&q->waitlist, dev->dma->buf_count);
+
+	return 0;
+}
+
+
+/* drm_alloc_queue:
+PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
+	disappear (so all deallocation must be done after IOCTLs are off)
+     2) dev->queue_count < dev->queue_slots
+     3) dev->queuelist[i].use_count == 0 and
+	dev->queuelist[i].finalization == 0 if i not in use 
+POST: 1) dev->queuelist[i].use_count == 1
+      2) dev->queue_count < dev->queue_slots */
+		
+static int drm_alloc_queue(drm_device_t *dev)
+{
+	int	    i;
+	drm_queue_t *queue;
+	int	    oldslots;
+	int	    newslots;
+				/* Check for a free queue */
+	for (i = 0; i < dev->queue_count; i++) {
+		atomic_inc(&dev->queuelist[i]->use_count);
+		if (atomic_read(&dev->queuelist[i]->use_count) == 1
+		    && !atomic_read(&dev->queuelist[i]->finalization)) {
+			DRM_DEBUG("%d (free)\n", i);
+			return i;
+		}
+		atomic_dec(&dev->queuelist[i]->use_count);
+	}
+				/* Allocate a new queue */
+	down(&dev->struct_sem);
+	
+	queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+	memset(queue, 0, sizeof(*queue));
+	atomic_set(&queue->use_count, 1);
+	
+	++dev->queue_count;
+	if (dev->queue_count >= dev->queue_slots) {
+		oldslots = dev->queue_slots * sizeof(*dev->queuelist);
+		if (!dev->queue_slots) dev->queue_slots = 1;
+		dev->queue_slots *= 2;
+		newslots = dev->queue_slots * sizeof(*dev->queuelist);
+
+		dev->queuelist = drm_realloc(dev->queuelist,
+					     oldslots,
+					     newslots,
+					     DRM_MEM_QUEUES);
+		if (!dev->queuelist) {
+			up(&dev->struct_sem);
+			DRM_DEBUG("out of memory\n");
+			return -ENOMEM;
+		}
+	}
+	dev->queuelist[dev->queue_count-1] = queue;
+	
+	up(&dev->struct_sem);
+	DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
+	return dev->queue_count - 1;
+}
+
+int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			copy_to_user_ret(&res.contexts[i],
+					 &i,
+					 sizeof(i),
+					 -EFAULT);
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+	return 0;
+}
+
+
+int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+				/* Init kernel's context and get a new one. */
+		drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+		ctx.handle = drm_alloc_queue(dev);
+	}
+	drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+	DRM_DEBUG("%d\n", ctx.handle);
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+		
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+
+	if (DRM_BUFCOUNT(&q->waitlist)) {
+		atomic_dec(&q->use_count);
+		return -EBUSY;
+	}
+	
+	q->flags = ctx.flags;
+	
+	atomic_dec(&q->use_count);
+	return 0;
+}
+
+int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+		
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+	
+	ctx.flags = q->flags;
+	atomic_dec(&q->use_count);
+	
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	
+	return 0;
+}
+
+int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	return drm_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	drm_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+	drm_buf_t	*buf;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+	
+	atomic_inc(&q->finalization); /* Mark queue in finalization state */
+	atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
+					 finalization) */
+
+	while (test_and_set_bit(0, &dev->interrupt_flag)) {
+		schedule();
+		if (signal_pending(current)) {
+			clear_bit(0, &dev->interrupt_flag);
+			return -EINTR;
+		}
+	}
+				/* Remove queued buffers */
+	while ((buf = drm_waitlist_get(&q->waitlist))) {
+		drm_free_buffer(dev, buf);
+	}
+	clear_bit(0, &dev->interrupt_flag);
+	
+				/* Wakeup blocked processes */
+	wake_up_interruptible(&q->read_queue);
+	wake_up_interruptible(&q->write_queue);
+	wake_up_interruptible(&q->flush_queue);
+	
+				/* Finalization over.  Queue is made
+				   available when both use_count and
+				   finalization become 0, which won't
+				   happen until all the waiting processes
+				   stop waiting. */
+	atomic_dec(&q->finalization);
+	return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/dma.c linux/drivers/char/drm/dma.c
--- v2.3.17/linux/drivers/char/drm/dma.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/dma.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,530 @@
+/* dma.c -- DMA IOCTL and function support -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:06:51 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/dma.c,v 1.6 1999/08/20 20:00:53 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+void drm_dma_setup(drm_device_t *dev)
+{
+	int i;
+	
+	dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
+	memset(dev->dma, 0, sizeof(*dev->dma));
+	for (i = 0; i <= DRM_MAX_ORDER; i++)
+		memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
+}
+
+void drm_dma_takedown(drm_device_t *dev)
+{
+	drm_device_dma_t  *dma = dev->dma;
+	int		  i, j;
+
+	if (!dma) return;
+	
+				/* Clear dma buffers */
+	for (i = 0; i <= DRM_MAX_ORDER; i++) {
+		if (dma->bufs[i].seg_count) {
+			DRM_DEBUG("order %d: buf_count = %d,"
+				  " seg_count = %d\n",
+				  i,
+				  dma->bufs[i].buf_count,
+				  dma->bufs[i].seg_count);
+			for (j = 0; j < dma->bufs[i].seg_count; j++) {
+				drm_free_pages(dma->bufs[i].seglist[j],
+					       dma->bufs[i].page_order,
+					       DRM_MEM_DMA);
+			}
+			drm_free(dma->bufs[i].buflist,
+				 dma->buf_count
+				 * sizeof(*dma->bufs[0].buflist),
+				 DRM_MEM_BUFS);
+			drm_free(dma->bufs[i].seglist,
+				 dma->buf_count
+				 * sizeof(*dma->bufs[0].seglist),
+				 DRM_MEM_SEGS);
+			drm_freelist_destroy(&dma->bufs[i].freelist);
+		}
+	}
+	
+	if (dma->buflist) {
+		drm_free(dma->buflist,
+			 dma->buf_count * sizeof(*dma->buflist),
+			 DRM_MEM_BUFS);
+	}
+
+	if (dma->pagelist) {
+		drm_free(dma->pagelist,
+			 dma->page_count * sizeof(*dma->pagelist),
+			 DRM_MEM_PAGES);
+	}
+	drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
+	dev->dma = NULL;
+}
+
+#if DRM_DMA_HISTOGRAM
+/* This is slow, but is useful for debugging. */
+int drm_histogram_slot(unsigned long count)
+{
+	int value = DRM_DMA_HISTOGRAM_INITIAL;
+	int slot;
+
+	for (slot = 0;
+	     slot < DRM_DMA_HISTOGRAM_SLOTS;
+	     ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) {
+		if (count < value) return slot;
+	}
+	return DRM_DMA_HISTOGRAM_SLOTS - 1;
+}
+
+void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf)
+{
+	cycles_t queued_to_dispatched;
+	cycles_t dispatched_to_completed;
+	cycles_t completed_to_freed;
+	int	 q2d, d2c, c2f, q2c, q2f;
+	
+	if (buf->time_queued) {
+		queued_to_dispatched	= (buf->time_dispatched
+					   - buf->time_queued);
+		dispatched_to_completed = (buf->time_completed
+					   - buf->time_dispatched);
+		completed_to_freed	= (buf->time_freed
+					   - buf->time_completed);
+
+		q2d = drm_histogram_slot(queued_to_dispatched);
+		d2c = drm_histogram_slot(dispatched_to_completed);
+		c2f = drm_histogram_slot(completed_to_freed);
+
+		q2c = drm_histogram_slot(queued_to_dispatched
+					 + dispatched_to_completed);
+		q2f = drm_histogram_slot(queued_to_dispatched
+					 + dispatched_to_completed
+					 + completed_to_freed);
+		
+		atomic_inc(&dev->histo.total);
+		atomic_inc(&dev->histo.queued_to_dispatched[q2d]);
+		atomic_inc(&dev->histo.dispatched_to_completed[d2c]);
+		atomic_inc(&dev->histo.completed_to_freed[c2f]);
+		
+		atomic_inc(&dev->histo.queued_to_completed[q2c]);
+		atomic_inc(&dev->histo.queued_to_freed[q2f]);
+
+	}
+	buf->time_queued     = 0;
+	buf->time_dispatched = 0;
+	buf->time_completed  = 0;
+	buf->time_freed	     = 0;
+}
+#endif
+
+void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
+{
+	drm_device_dma_t *dma = dev->dma;
+
+	if (!buf) return;
+	
+	buf->waiting  = 0;
+	buf->pending  = 0;
+	buf->pid      = 0;
+	buf->used     = 0;
+#if DRM_DMA_HISTOGRAM
+	buf->time_completed = get_cycles();
+#endif
+	if (waitqueue_active(&buf->dma_wait)) {
+		wake_up_interruptible(&buf->dma_wait);
+	} else {
+				/* If processes are waiting, the last one
+				   to wake will put the buffer on the free
+				   list.  If no processes are waiting, we
+				   put the buffer on the freelist here. */
+		drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf);
+	}
+}
+
+void drm_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	for (i = 0; i < dma->buf_count; i++) {
+		if (dma->buflist[i]->pid == pid) {
+			switch (dma->buflist[i]->list) {
+			case DRM_LIST_NONE:
+				drm_free_buffer(dev, dma->buflist[i]);
+				break;
+			case DRM_LIST_WAIT:
+				dma->buflist[i]->list = DRM_LIST_RECLAIM;
+				break;
+			default:
+				/* Buffer already on hardware. */
+				break;
+			}
+		}
+	}
+}
+
+int drm_context_switch(drm_device_t *dev, int old, int new)
+{
+	char	    buf[64];
+	drm_queue_t *q;
+
+	atomic_inc(&dev->total_ctx);
+
+	if (test_and_set_bit(0, &dev->context_flag)) {
+		DRM_ERROR("Reentering -- FIXME\n");
+		return -EBUSY;
+	}
+
+#if DRM_DMA_HISTOGRAM
+	dev->ctx_start = get_cycles();
+#endif
+	
+	DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+	if (new >= dev->queue_count) {
+		clear_bit(0, &dev->context_flag);
+		return -EINVAL;
+	}
+
+	if (new == dev->last_context) {
+		clear_bit(0, &dev->context_flag);
+		return 0;
+	}
+	
+	q = dev->queuelist[new];
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+		atomic_dec(&q->use_count);
+		clear_bit(0, &dev->context_flag);
+		return -EINVAL;
+	}
+
+	if (drm_flags & DRM_FLAG_NOCTX) {
+		drm_context_switch_complete(dev, new);
+	} else {
+		sprintf(buf, "C %d %d\n", old, new);
+		drm_write_string(dev, buf);
+	}
+	
+	atomic_dec(&q->use_count);
+	
+	return 0;
+}
+
+int drm_context_switch_complete(drm_device_t *dev, int new)
+{
+	drm_device_dma_t *dma = dev->dma;
+	
+	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+	dev->last_switch  = jiffies;
+	
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("Lock isn't held after context switch\n");
+	}
+
+	if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("Cannot free lock\n");
+		}
+	}
+	
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+						      - dev->ctx_start)]);
+		   
+#endif
+	clear_bit(0, &dev->context_flag);
+	wake_up_interruptible(&dev->context_wait);
+	
+	return 0;
+}
+
+void drm_clear_next_buffer(drm_device_t *dev)
+{
+	drm_device_dma_t *dma = dev->dma;
+	
+	dma->next_buffer = NULL;
+	if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
+		wake_up_interruptible(&dma->next_queue->flush_queue);
+	}
+	dma->next_queue	 = NULL;
+}
+
+
+int drm_select_queue(drm_device_t *dev, void (*wrapper)(unsigned long))
+{
+	int	   i;
+	int	   candidate = -1;
+	int	   j	     = jiffies;
+
+	if (!dev) {
+		DRM_ERROR("No device\n");
+		return -1;
+	}
+	if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
+				/* This only happens between the time the
+				   interrupt is initialized and the time
+				   the queues are initialized. */
+		return -1;
+	}
+
+				/* Doing "while locked" DMA? */
+	if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
+		return DRM_KERNEL_CONTEXT;
+	}
+
+				/* If there are buffers on the last_context
+				   queue, and we have not been executing
+				   this context very long, continue to
+				   execute this context. */
+	if (dev->last_switch <= j
+	    && dev->last_switch + DRM_TIME_SLICE > j
+	    && DRM_WAITCOUNT(dev, dev->last_context)) {
+		return dev->last_context;
+	}
+
+				/* Otherwise, find a candidate */
+	for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
+		if (DRM_WAITCOUNT(dev, i)) {
+			candidate = dev->last_checked = i;
+			break;
+		}
+	}
+
+	if (candidate < 0) {
+		for (i = 0; i < dev->queue_count; i++) {
+			if (DRM_WAITCOUNT(dev, i)) {
+				candidate = dev->last_checked = i;
+				break;
+			}
+		}
+	}
+
+	if (wrapper
+	    && candidate >= 0
+	    && candidate != dev->last_context
+	    && dev->last_switch <= j
+	    && dev->last_switch + DRM_TIME_SLICE > j) {
+		if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
+			del_timer(&dev->timer);
+			dev->timer.function = wrapper;
+			dev->timer.data	    = (unsigned long)dev;
+			dev->timer.expires  = dev->last_switch+DRM_TIME_SLICE;
+			add_timer(&dev->timer);
+		}
+		return -1;
+	}
+
+	return candidate;
+}
+
+
+int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
+{
+	int		  i;
+	drm_queue_t	  *q;
+	drm_buf_t	  *buf;
+	int		  idx;
+	int		  while_locked = 0;
+	drm_device_dma_t  *dma = dev->dma;
+	DECLARE_WAITQUEUE(entry, current);
+
+	DRM_DEBUG("%d\n", d->send_count);
+
+	if (d->flags & _DRM_DMA_WHILE_LOCKED) {
+		int context = dev->lock.hw_lock->lock;
+		
+		if (!_DRM_LOCK_IS_HELD(context)) {
+			DRM_ERROR("No lock held during \"while locked\""
+				  " request\n");
+			return -EINVAL;
+		}
+		if (d->context != _DRM_LOCKING_CONTEXT(context)
+		    && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
+			DRM_ERROR("Lock held by %d while %d makes"
+				  " \"while locked\" request\n",
+				  _DRM_LOCKING_CONTEXT(context),
+				  d->context);
+			return -EINVAL;
+		}
+		q = dev->queuelist[DRM_KERNEL_CONTEXT];
+		while_locked = 1;
+	} else {
+		q = dev->queuelist[d->context];
+	}
+
+
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->block_write)) {
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&q->write_queue, &entry);
+		atomic_inc(&q->block_count);
+		for (;;) {
+			if (!atomic_read(&q->block_write)) break;
+			schedule();
+			if (signal_pending(current)) {
+				atomic_dec(&q->use_count);
+				return -EINTR;
+			}
+		}
+		atomic_dec(&q->block_count);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&q->write_queue, &entry);
+	}
+	
+	for (i = 0; i < d->send_count; i++) {
+		idx = d->send_indices[i];
+		if (idx < 0 || idx >= dma->buf_count) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Index %d (of %d max)\n",
+				  d->send_indices[i], dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[ idx ];
+		if (buf->pid != current->pid) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Process %d using buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		if (buf->list != DRM_LIST_NONE) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Process %d using buffer %d on list %d\n",
+				  current->pid, buf->idx, buf->list);
+		}
+		buf->used	  = d->send_sizes[i];
+		buf->while_locked = while_locked;
+		buf->context	  = d->context;
+		if (!buf->used) {
+			DRM_ERROR("Queueing 0 length buffer\n");
+		}
+		if (buf->pending) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Queueing pending buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			return -EINVAL;
+		}
+		if (buf->waiting) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Queueing waiting buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			return -EINVAL;
+		}
+		buf->waiting = 1;
+		if (atomic_read(&q->use_count) == 1
+		    || atomic_read(&q->finalization)) {
+			drm_free_buffer(dev, buf);
+		} else {
+			drm_waitlist_put(&q->waitlist, buf);
+			atomic_inc(&q->total_queued);
+		}
+	}
+	atomic_dec(&q->use_count);
+	
+	return 0;
+}
+
+static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d,
+					int order)
+{
+	int		  i;
+	drm_buf_t	  *buf;
+	drm_device_dma_t  *dma = dev->dma;
+	
+	for (i = d->granted_count; i < d->request_count; i++) {
+		buf = drm_freelist_get(&dma->bufs[order].freelist,
+				       d->flags & _DRM_DMA_WAIT);
+		if (!buf) break;
+		if (buf->pending || buf->waiting) {
+			DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n",
+				  buf->idx,
+				  buf->pid,
+				  buf->waiting,
+				  buf->pending);
+		}
+		buf->pid     = current->pid;
+		copy_to_user_ret(&d->request_indices[i],
+				 &buf->idx,
+				 sizeof(buf->idx),
+				 -EFAULT);
+		copy_to_user_ret(&d->request_sizes[i],
+				 &buf->total,
+				 sizeof(buf->total),
+				 -EFAULT);
+		++d->granted_count;
+	}
+	return 0;
+}
+
+
+int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma)
+{
+	int		  order;
+	int		  retcode = 0;
+	int		  tmp_order;
+	
+	order = drm_order(dma->request_size);
+
+	dma->granted_count = 0;
+	retcode		   = drm_dma_get_buffers_of_order(dev, dma, order);
+
+	if (dma->granted_count < dma->request_count
+	    && (dma->flags & _DRM_DMA_SMALLER_OK)) {
+		for (tmp_order = order - 1;
+		     !retcode
+			     && dma->granted_count < dma->request_count
+			     && tmp_order >= DRM_MIN_ORDER;
+		     --tmp_order) {
+			
+			retcode = drm_dma_get_buffers_of_order(dev, dma,
+							       tmp_order);
+		}
+	}
+
+	if (dma->granted_count < dma->request_count
+	    && (dma->flags & _DRM_DMA_LARGER_OK)) {
+		for (tmp_order = order + 1;
+		     !retcode
+			     && dma->granted_count < dma->request_count
+			     && tmp_order <= DRM_MAX_ORDER;
+		     ++tmp_order) {
+			
+			retcode = drm_dma_get_buffers_of_order(dev, dma,
+							       tmp_order);
+		}
+	}
+	return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/drawable.c linux/drivers/char/drm/drawable.c
--- v2.3.17/linux/drivers/char/drm/drawable.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/drawable.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,50 @@
+/* drawable.c -- IOCTLs for drawables -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:03 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drawable.c,v 1.3 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_draw_t draw;
+
+	draw.handle = 0;	/* NOOP */
+	DRM_DEBUG("%d\n", draw.handle);
+	copy_to_user_ret((drm_draw_t *)arg, &draw, sizeof(draw), -EFAULT);
+	return 0;
+}
+
+int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	return 0;		/* NOOP */
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/drm.h linux/drivers/char/drm/drm.h
--- v2.3.17/linux/drivers/char/drm/drm.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/drm.h	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,277 @@
+/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:08:18 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.46 1999/08/20 20:00:53 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drm.h,v 1.2 1999/06/27 14:08:21 dawes Exp $
+ * 
+ */
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#include <asm/ioctl.h>		/* For _IO* macros */
+
+#define DRM_PROC_DEVICES "/proc/devices"
+#define DRM_PROC_MISC	 "/proc/misc"
+#define DRM_PROC_DRM	 "/proc/drm"
+#define DRM_DEV_DRM	 "/dev/drm"
+#define DRM_DEV_MODE	 (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+#define DRM_DEV_UID	 0
+#define DRM_DEV_GID	 0
+
+
+#define DRM_NAME	"drm"	  /* Name in kernel, /dev, and /proc	    */
+#define DRM_MIN_ORDER	5	  /* At least 2^5 bytes = 32 bytes	    */
+#define DRM_MAX_ORDER	22	  /* Up to 2^22 bytes = 4MB		    */
+#define DRM_RAM_PERCENT 10	  /* How much system ram can we lock?	    */
+
+#define _DRM_LOCK_HELD	0x80000000 /* Hardware lock is held		    */
+#define _DRM_LOCK_CONT	0x40000000 /* Hardware lock is contended	    */
+#define _DRM_LOCK_IS_HELD(lock)	   ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock)	   ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+typedef unsigned long drm_handle_t;
+typedef unsigned int  drm_context_t;
+typedef unsigned int  drm_drawable_t;
+typedef unsigned int  drm_magic_t;
+
+
+typedef struct drm_version {
+	int    version_major;	  /* Major version			    */
+	int    version_minor;	  /* Minor version			    */
+	int    version_patchlevel;/* Patch level			    */
+	size_t name_len;	  /* Length of name buffer		    */
+	char   *name;		  /* Name of driver			    */
+	size_t date_len;	  /* Length of date buffer		    */
+	char   *date;		  /* User-space buffer to hold date	    */
+	size_t desc_len;	  /* Length of desc buffer		    */
+	char   *desc;		  /* User-space buffer to hold desc	    */
+} drm_version_t;
+
+typedef struct drm_unique {
+	size_t unique_len;	  /* Length of unique			    */
+	char   *unique;		  /* Unique name for driver instantiation   */
+} drm_unique_t;
+
+typedef struct drm_list {
+	int		 count;	  /* Length of user-space structures	    */
+	drm_version_t	 *version;
+} drm_list_t;
+
+typedef struct drm_block {
+	int		 unused;
+} drm_block_t;
+
+typedef struct drm_control {
+	enum {
+		DRM_ADD_COMMAND,
+		DRM_RM_COMMAND,
+		DRM_INST_HANDLER,
+		DRM_UNINST_HANDLER
+	}		 func;
+	int		 irq;
+} drm_control_t;
+
+typedef enum drm_map_type {
+	_DRM_FRAME_BUFFER = 0,	  /* WC (no caching), no core dump	    */
+	_DRM_REGISTERS	  = 1,	  /* no caching, no core dump		    */
+	_DRM_SHM	  = 2	  /* shared, cached			    */
+} drm_map_type_t;
+
+typedef enum drm_map_flags {
+	_DRM_RESTRICTED	     = 0x01, /* Cannot be mapped to user-virtual    */
+	_DRM_READ_ONLY	     = 0x02,
+	_DRM_LOCKED	     = 0x04, /* shared, cached, locked		    */
+	_DRM_KERNEL	     = 0x08, /* kernel requires access		    */
+	_DRM_WRITE_COMBINING = 0x10, /* use write-combining if available    */
+	_DRM_CONTAINS_LOCK   = 0x20  /* SHM page that contains lock	    */
+} drm_map_flags_t;
+
+typedef struct drm_map {
+	unsigned long	offset;	 /* Requested physical address (0 for SAREA)*/
+	unsigned long	size;	 /* Requested physical size (bytes)	    */
+	drm_map_type_t	type;	 /* Type of memory to map		    */
+	drm_map_flags_t flags;	 /* Flags				    */
+	void		*handle; /* User-space: "Handle" to pass to mmap    */
+				 /* Kernel-space: kernel-virtual address    */
+	int		mtrr;	 /* MTRR slot used			    */
+				 /* Private data			    */
+} drm_map_t;
+
+typedef enum drm_lock_flags {
+	_DRM_LOCK_READY	     = 0x01, /* Wait until hardware is ready for DMA */
+	_DRM_LOCK_QUIESCENT  = 0x02, /* Wait until hardware quiescent	     */
+	_DRM_LOCK_FLUSH	     = 0x04, /* Flush this context's DMA queue first */
+	_DRM_LOCK_FLUSH_ALL  = 0x08, /* Flush all DMA queues first	     */
+				/* These *HALT* flags aren't supported yet
+				   -- they will be used to support the
+				   full-screen DGA-like mode. */
+	_DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues   */
+	_DRM_HALT_CUR_QUEUES = 0x20  /* Halt all current queues		     */
+} drm_lock_flags_t;
+
+typedef struct drm_lock {
+	int		 context;
+	drm_lock_flags_t flags;
+} drm_lock_t;
+
+typedef enum drm_dma_flags {	      /* These values *MUST* match xf86drm.h */
+				      /* Flags for DMA buffer dispatch	     */
+	_DRM_DMA_BLOCK	      = 0x01, /* Block until buffer dispatched.
+					 Note, the buffer may not yet have
+					 been processed by the hardware --
+					 getting a hardware lock with the
+					 hardware quiescent will ensure
+					 that the buffer has been
+					 processed.			     */
+	_DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held	     */
+	_DRM_DMA_PRIORITY     = 0x04, /* High priority dispatch		     */
+
+				      /* Flags for DMA buffer request	     */
+	_DRM_DMA_WAIT	      = 0x10, /* Wait for free buffers		     */
+	_DRM_DMA_SMALLER_OK   = 0x20, /* Smaller-than-requested buffers ok   */
+	_DRM_DMA_LARGER_OK    = 0x40  /* Larger-than-requested buffers ok    */
+} drm_dma_flags_t;
+
+typedef struct drm_buf_desc {
+	int	      count;	 /* Number of buffers of this size	     */
+	int	      size;	 /* Size in bytes			     */
+	int	      low_mark;	 /* Low water mark			     */
+	int	      high_mark; /* High water mark			     */
+	enum {
+		DRM_PAGE_ALIGN = 0x01  /* Align on page boundaries for DMA   */
+	}	      flags;
+} drm_buf_desc_t;
+
+typedef struct drm_buf_info {
+	int	       count;	/* Entries in list			     */
+	drm_buf_desc_t *list;
+} drm_buf_info_t;
+
+typedef struct drm_buf_free {
+	int	       count;
+	int	       *list;
+} drm_buf_free_t;
+
+typedef struct drm_buf_pub {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	void		  *address;    /* Address of buffer		     */
+} drm_buf_pub_t;
+
+typedef struct drm_buf_map {
+	int	      count;	/* Length of buflist			    */
+	void	      *virtual;	/* Mmaped area in user-virtual		    */
+	drm_buf_pub_t *list;	/* Buffer information			    */
+} drm_buf_map_t;
+
+typedef struct drm_dma {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		context;	  /* Context handle		    */
+	int		send_count;	  /* Number of buffers to send	    */
+	int		*send_indices;	  /* List of handles to buffers	    */
+	int		*send_sizes;	  /* Lengths of data to send	    */
+	drm_dma_flags_t flags;		  /* Flags			    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		request_size;	  /* Desired size for buffers	    */
+	int		*request_indices; /* Buffer information		    */
+	int		*request_sizes;
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm_dma_t;
+
+typedef enum {
+	_DRM_CONTEXT_PRESERVED = 0x01,
+	_DRM_CONTEXT_2DONLY    = 0x02
+} drm_ctx_flags_t;
+
+typedef struct drm_ctx {
+	drm_context_t	handle;
+	drm_ctx_flags_t flags;
+} drm_ctx_t;
+
+typedef struct drm_ctx_res {
+	int		count;
+	drm_ctx_t	*contexts;
+} drm_ctx_res_t;
+
+typedef struct drm_draw {
+	drm_drawable_t	handle;
+} drm_draw_t;
+
+typedef struct drm_auth {
+	drm_magic_t	magic;
+} drm_auth_t;
+
+typedef struct drm_irq_busid {
+	int irq;
+	int busnum;
+	int devnum;
+	int funcnum;
+} drm_irq_busid_t;
+
+#define DRM_IOCTL_BASE	     'd'
+#define DRM_IOCTL_NR(n)	     _IOC_NR(n)
+#define DRM_IO(nr)	     _IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,size)     _IOR(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOW(nr,size)     _IOW(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOWR(nr,size)    _IOWR(DRM_IOCTL_BASE,nr,size)
+
+
+#define DRM_IOCTL_VERSION    DRM_IOWR(0x00, drm_version_t)
+#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
+#define DRM_IOCTL_GET_MAGIC  DRM_IOW( 0x02, drm_auth_t)
+#define DRM_IOCTL_IRQ_BUSID  DRM_IOWR(0x03, drm_irq_busid_t)
+
+#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
+#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t)
+#define DRM_IOCTL_BLOCK	     DRM_IOWR(0x12, drm_block_t)
+#define DRM_IOCTL_UNBLOCK    DRM_IOWR(0x13, drm_block_t)
+#define DRM_IOCTL_CONTROL    DRM_IOW( 0x14, drm_control_t)
+#define DRM_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm_map_t)
+#define DRM_IOCTL_ADD_BUFS   DRM_IOWR(0x16, drm_buf_desc_t)
+#define DRM_IOCTL_MARK_BUFS  DRM_IOW( 0x17, drm_buf_desc_t)
+#define DRM_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm_buf_info_t)
+#define DRM_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm_buf_map_t)
+#define DRM_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm_buf_free_t)
+
+#define DRM_IOCTL_ADD_CTX    DRM_IOWR(0x20, drm_ctx_t)
+#define DRM_IOCTL_RM_CTX     DRM_IOWR(0x21, drm_ctx_t)
+#define DRM_IOCTL_MOD_CTX    DRM_IOW( 0x22, drm_ctx_t)
+#define DRM_IOCTL_GET_CTX    DRM_IOWR(0x23, drm_ctx_t)
+#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t)
+#define DRM_IOCTL_NEW_CTX    DRM_IOW( 0x25, drm_ctx_t)
+#define DRM_IOCTL_RES_CTX    DRM_IOWR(0x26, drm_ctx_res_t)
+#define DRM_IOCTL_ADD_DRAW   DRM_IOWR(0x27, drm_draw_t)
+#define DRM_IOCTL_RM_DRAW    DRM_IOWR(0x28, drm_draw_t)
+#define DRM_IOCTL_DMA	     DRM_IOWR(0x29, drm_dma_t)
+#define DRM_IOCTL_LOCK	     DRM_IOW( 0x2a, drm_lock_t)
+#define DRM_IOCTL_UNLOCK     DRM_IOW( 0x2b, drm_lock_t)
+#define DRM_IOCTL_FINISH     DRM_IOW( 0x2c, drm_lock_t)
+
+#endif
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h
--- v2.3.17/linux/drivers/char/drm/drmP.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/drmP.h	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,584 @@
+/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.58 1999/08/30 13:05:00 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/drmP.h,v 1.2 1999/06/27 14:08:24 dawes Exp $
+ * 
+ */
+
+#ifndef _DRM_P_H_
+#define _DRM_P_H_
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/pci.h>
+#include <linux/wrapper.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#include "drm.h"
+
+#define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then
+				     also include looping detection. */
+#define DRM_DMA_HISTOGRAM 1	  /* Make histogram of DMA latency. */
+
+#define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
+#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
+#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
+#define DRM_LOOPING_LIMIT     5000000
+#define DRM_BSZ		      1024 /* Buffer size for /dev/drm? output	  */
+#define DRM_TIME_SLICE	      (HZ/20)  /* Time slice for GLXContexts	  */
+#define DRM_LOCK_SLICE	      1	/* Time slice for lock, in jiffies	  */
+
+#define DRM_FLAG_DEBUG	  0x01
+#define DRM_FLAG_NOCTX	  0x02
+
+#define DRM_MEM_DMA	  0
+#define DRM_MEM_SAREA	  1
+#define DRM_MEM_DRIVER	  2
+#define DRM_MEM_MAGIC	  3
+#define DRM_MEM_IOCTLS	  4
+#define DRM_MEM_MAPS	  5
+#define DRM_MEM_VMAS	  6
+#define DRM_MEM_BUFS	  7
+#define DRM_MEM_SEGS	  8
+#define DRM_MEM_PAGES	  9
+#define DRM_MEM_FILES	 10
+#define DRM_MEM_QUEUES	 11
+#define DRM_MEM_CMDS	 12
+#define DRM_MEM_MAPPINGS 13
+#define DRM_MEM_BUFLISTS 14
+
+				/* Backward compatibility section */
+#ifndef _PAGE_PWT
+				/* The name of _PAGE_WT was changed to
+				   _PAGE_PWT in Linux 2.2.6 */
+#define _PAGE_PWT _PAGE_WT
+#endif
+				/* Wait queue declarations changes in 2.3.1 */
+#ifndef DECLARE_WAITQUEUE
+#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL }
+typedef struct wait_queue *wait_queue_head_t;
+#define init_waitqueue_head(q) *q = NULL;
+#endif
+
+#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock)
+#define _DRM_CAS(lock,old,new,__ret)				       \
+	do {							       \
+		int __dummy;	/* Can't mark eax as clobbered */      \
+		__asm__ __volatile__(				       \
+			"lock ; cmpxchg %4,%1\n\t"		       \
+			"setnz %0"				       \
+			: "=d" (__ret),				       \
+			  "=m" (__drm_dummy_lock(lock)),	       \
+			  "=a" (__dummy)			       \
+			: "2" (old),				       \
+			  "r" (new));				       \
+	} while (0)
+
+
+
+				/* Macros to make printk easier */
+#define DRM_ERROR(fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg)
+#define DRM_MEM_ERROR(area, fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \
+	       drm_mem_stats[area].name , ##arg)
+#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+
+#if DRM_DEBUG_CODE
+#define DRM_DEBUG(fmt, arg...)						  \
+	do {								  \
+		if (drm_flags&DRM_FLAG_DEBUG)				  \
+			printk(KERN_DEBUG				  \
+			       "[" DRM_NAME ":" __FUNCTION__ "] " fmt ,	  \
+			       ##arg);					  \
+	} while (0)
+#else
+#define DRM_DEBUG(fmt, arg...)		 do { } while (0)
+#endif
+
+#define DRM_PROC_LIMIT (PAGE_SIZE-80)
+
+#define DRM_PROC_PRINT(fmt, arg...)	   \
+   len += sprintf(&buf[len], fmt , ##arg); \
+   if (len > DRM_PROC_LIMIT) return len;
+
+#define DRM_PROC_PRINT_RET(ret, fmt, arg...)	    \
+   len += sprintf(&buf[len], fmt , ##arg);	    \
+   if (len > DRM_PROC_LIMIT) { ret; return len; }
+
+				/* Internal types and structures */
+#define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define DRM_MIN(a,b) ((a)<(b)?(a):(b))
+#define DRM_MAX(a,b) ((a)>(b)?(a):(b))
+
+#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
+#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
+#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
+
+typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+
+typedef struct drm_ioctl_desc {
+	drm_ioctl_t	     *func;
+	int		     auth_needed;
+	int		     root_only;
+} drm_ioctl_desc_t;
+
+typedef struct drm_devstate {
+	pid_t		  owner;	/* X server pid holding x_lock */
+	
+} drm_devstate_t;
+
+typedef struct drm_magic_entry {
+	drm_magic_t	       magic;
+	struct drm_file	       *priv;
+	struct drm_magic_entry *next;
+} drm_magic_entry_t;
+
+typedef struct drm_magic_head {
+       struct drm_magic_entry *head;
+       struct drm_magic_entry *tail;
+} drm_magic_head_t;
+
+typedef struct drm_vma_entry {
+	struct vm_area_struct *vma;
+	struct drm_vma_entry  *next;
+	pid_t		      pid;
+} drm_vma_entry_t;
+
+typedef struct drm_buf {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  order;       /* log-base-2(total)		     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	unsigned long	  offset;      /* Byte offset (used internally)	     */
+	void		  *address;    /* Address of buffer		     */
+	struct drm_buf	  *next;       /* Kernel-only: used for free list    */
+	__volatile__ int  waiting;     /* On kernel DMA queue		     */
+	__volatile__ int  pending;     /* On hardware DMA queue		     */
+	wait_queue_head_t dma_wait;    /* Processes waiting		     */
+	pid_t		  pid;	       /* PID of holding process	     */
+	int		  context;     /* Kernel queue for this buffer	     */
+	int		  while_locked;/* Dispatch this buffer while locked  */
+	enum {
+		DRM_LIST_NONE	 = 0,
+		DRM_LIST_FREE	 = 1,
+		DRM_LIST_WAIT	 = 2,
+		DRM_LIST_PEND	 = 3,
+		DRM_LIST_PRIO	 = 4,
+		DRM_LIST_RECLAIM = 5
+	}		  list;	       /* Which list we're on		     */
+#if DRM_DMA_HISTOGRAM
+	cycles_t	  time_queued;	   /* Queued to kernel DMA queue     */
+	cycles_t	  time_dispatched; /* Dispatched to hardware	     */
+	cycles_t	  time_completed;  /* Completed by hardware	     */
+	cycles_t	  time_freed;	   /* Back on freelist		     */
+#endif
+} drm_buf_t;
+
+#if DRM_DMA_HISTOGRAM
+#define DRM_DMA_HISTOGRAM_SLOTS		  9
+#define DRM_DMA_HISTOGRAM_INITIAL	 10
+#define DRM_DMA_HISTOGRAM_NEXT(current)	 ((current)*10)
+typedef struct drm_histogram {
+	atomic_t	  total;
+	
+	atomic_t	  queued_to_dispatched[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  dispatched_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  completed_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+	
+	atomic_t	  queued_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  queued_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+	
+	atomic_t	  dma[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  schedule[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  ctx[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  lacq[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  lhld[DRM_DMA_HISTOGRAM_SLOTS];
+} drm_histogram_t;
+#endif
+
+				/* bufs is one longer than it has to be */
+typedef struct drm_waitlist {
+	int		  count;	/* Number of possible buffers	   */
+	drm_buf_t	  **bufs;	/* List of pointers to buffers	   */
+	drm_buf_t	  **rp;		/* Read pointer			   */
+	drm_buf_t	  **wp;		/* Write pointer		   */
+	drm_buf_t	  **end;	/* End pointer			   */
+	spinlock_t	  read_lock;
+	spinlock_t	  write_lock;
+} drm_waitlist_t;
+
+typedef struct drm_freelist {
+	int		  initialized; /* Freelist in use		   */
+	atomic_t	  count;       /* Number of free buffers	   */
+	drm_buf_t	  *next;       /* End pointer			   */
+	
+	wait_queue_head_t waiting;     /* Processes waiting on free bufs   */
+	int		  low_mark;    /* Low water mark		   */
+	int		  high_mark;   /* High water mark		   */
+	atomic_t	  wfh;	       /* If waiting for high mark	   */
+} drm_freelist_t;
+
+typedef struct drm_buf_entry {
+	int		  buf_size;
+	int		  buf_count;
+	drm_buf_t	  *buflist;
+	int		  seg_count;
+	int		  page_order;
+	unsigned long	  *seglist;
+
+	drm_freelist_t	  freelist;
+} drm_buf_entry_t;
+
+typedef struct drm_hw_lock {
+	__volatile__ unsigned int lock;
+	char			  padding[60]; /* Pad to cache line */
+} drm_hw_lock_t;
+
+typedef struct drm_file {
+	int		  authenticated;
+	int		  minor;
+	pid_t		  pid;
+	uid_t		  uid;
+	drm_magic_t	  magic;
+	unsigned long	  ioctl_count;
+	struct drm_file	  *next;
+	struct drm_file	  *prev;
+	struct drm_device *dev;
+} drm_file_t;
+
+
+typedef struct drm_queue {
+	atomic_t	  use_count;	/* Outstanding uses (+1)	    */
+	atomic_t	  finalization;	/* Finalization in progress	    */
+	atomic_t	  block_count;	/* Count of processes waiting	    */
+	atomic_t	  block_read;	/* Queue blocked for reads	    */
+	wait_queue_head_t read_queue;	/* Processes waiting on block_read  */
+	atomic_t	  block_write;	/* Queue blocked for writes	    */
+	wait_queue_head_t write_queue;	/* Processes waiting on block_write */
+	atomic_t	  total_queued;	/* Total queued statistic	    */
+	atomic_t	  total_flushed;/* Total flushes statistic	    */
+	atomic_t	  total_locks;	/* Total locks statistics	    */
+	drm_ctx_flags_t	  flags;	/* Context preserving and 2D-only   */
+	drm_waitlist_t	  waitlist;	/* Pending buffers		    */
+	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+} drm_queue_t;
+
+typedef struct drm_lock_data {
+	drm_hw_lock_t	  *hw_lock;	/* Hardware lock		   */
+	pid_t		  pid;		/* PID of lock holder (0=kernel)   */
+	wait_queue_head_t lock_queue;	/* Queue of blocked processes	   */
+	unsigned long	  lock_time;	/* Time of last lock in jiffies	   */
+} drm_lock_data_t;
+
+typedef struct drm_device_dma {
+				/* Performance Counters */
+	atomic_t	  total_prio;	/* Total DRM_DMA_PRIORITY	   */
+	atomic_t	  total_bytes;	/* Total bytes DMA'd		   */
+	atomic_t	  total_dmas;	/* Total DMA buffers dispatched	   */
+	
+	atomic_t	  total_missed_dma;  /* Missed drm_do_dma	    */
+	atomic_t	  total_missed_lock; /* Missed lock in drm_do_dma   */
+	atomic_t	  total_missed_free; /* Missed drm_free_this_buffer */
+	atomic_t	  total_missed_sched;/* Missed drm_dma_schedule	    */
+
+	atomic_t	  total_tried;	/* Tried next_buffer		    */
+	atomic_t	  total_hit;	/* Sent next_buffer		    */
+	atomic_t	  total_lost;	/* Lost interrupt		    */
+
+	drm_buf_entry_t	  bufs[DRM_MAX_ORDER+1];
+	int		  buf_count;
+	drm_buf_t	  **buflist;	/* Vector of pointers info bufs	   */
+	int		  seg_count; 
+	int		  page_count;
+	unsigned long	  *pagelist;
+	unsigned long	  byte_count;
+
+				/* DMA support */
+	drm_buf_t	  *this_buffer;	/* Buffer being sent		   */
+	drm_buf_t	  *next_buffer; /* Selected buffer to send	   */
+	drm_queue_t	  *next_queue;	/* Queue from which buffer selected*/
+	wait_queue_head_t waiting;	/* Processes waiting on free bufs  */
+} drm_device_dma_t;
+
+typedef struct drm_device {
+	const char	  *name;	/* Simple driver name		   */
+	char		  *unique;	/* Unique identifier: e.g., busid  */
+	int		  unique_len;	/* Length of unique field	   */
+	dev_t		  device;	/* Device number for mknod	   */
+	char		  *devname;	/* For /proc/interrupts		   */
+	
+	int		  blocked;	/* Blocked due to VC switch?	   */
+	struct proc_dir_entry *root;	/* Root for this device's entries  */
+
+				/* Locks */
+	spinlock_t	  count_lock;	/* For inuse, open_count, buf_use  */
+	struct semaphore  struct_sem;	/* For others			   */
+
+				/* Usage Counters */
+	int		  open_count;	/* Outstanding files open	   */
+	atomic_t	  ioctl_count;	/* Outstanding IOCTLs pending	   */
+	atomic_t	  vma_count;	/* Outstanding vma areas open	   */
+	int		  buf_use;	/* Buffers in use -- cannot alloc  */
+	atomic_t	  buf_alloc;	/* Buffer allocation in progress   */
+
+				/* Performance Counters */
+	atomic_t	  total_open;
+	atomic_t	  total_close;
+	atomic_t	  total_ioctl;
+	atomic_t	  total_irq;	/* Total interruptions		   */
+	atomic_t	  total_ctx;	/* Total context switches	   */
+	
+	atomic_t	  total_locks;
+	atomic_t	  total_unlocks;
+	atomic_t	  total_contends;
+	atomic_t	  total_sleeps;
+
+				/* Authentication */
+	drm_file_t	  *file_first;
+	drm_file_t	  *file_last;
+	drm_magic_head_t  magiclist[DRM_HASH_SIZE];
+
+				/* Memory management */
+	drm_map_t	  **maplist;	/* Vector of pointers to regions   */
+	int		  map_count;	/* Number of mappable regions	   */
+
+	drm_vma_entry_t	  *vmalist;	/* List of vmas (for debugging)	   */
+	drm_lock_data_t	  lock;		/* Information on hardware lock	   */
+
+				/* DMA queues (contexts) */
+	int		  queue_count;	/* Number of active DMA queues	   */
+	int		  queue_reserved; /* Number of reserved DMA queues */
+	int		  queue_slots;	/* Actual length of queuelist	   */
+	drm_queue_t	  **queuelist;	/* Vector of pointers to DMA queues */
+	drm_device_dma_t  *dma;		/* Optional pointer for DMA support */
+
+				/* Context support */
+	int		  irq;		/* Interrupt used by board	   */
+	__volatile__ int  context_flag;	 /* Context swapping flag	   */
+	__volatile__ int  interrupt_flag;/* Interruption handler flag	   */
+	__volatile__ int  dma_flag;	 /* DMA dispatch flag		   */
+	struct timer_list timer;	/* Timer for delaying ctx switch   */
+	wait_queue_head_t context_wait; /* Processes waiting on ctx switch */
+	int		  last_checked;	/* Last context checked for DMA	   */
+	int		  last_context;	/* Last current context		   */
+	unsigned long	  last_switch;	/* jiffies at last context switch  */
+	struct tq_struct  tq;
+	cycles_t	  ctx_start;
+	cycles_t	  lck_start;
+#if DRM_DMA_HISTOGRAM
+	drm_histogram_t	  histo;
+#endif
+	
+				/* Callback to X server for context switch
+				   and for heavy-handed reset. */
+	char		  buf[DRM_BSZ]; /* Output buffer		   */
+	char		  *buf_rp;	/* Read pointer			   */
+	char		  *buf_wp;	/* Write pointer		   */
+	char		  *buf_end;	/* End pointer			   */
+	struct fasync_struct *buf_async;/* Processes waiting for SIGIO	   */
+	wait_queue_head_t buf_readers;	/* Processes waiting to read	   */
+	wait_queue_head_t buf_writers;	/* Processes waiting to ctx switch */
+} drm_device_t;
+
+
+				/* Internal function definitions */
+
+				/* Misc. support (init.c) */
+extern int	     drm_flags;
+extern void	     drm_parse_options(char *s);
+
+
+				/* Device support (fops.c) */
+extern int	     drm_open_helper(struct inode *inode, struct file *filp,
+				     drm_device_t *dev);
+extern int	     drm_flush(struct file *filp);
+extern int	     drm_release(struct inode *inode, struct file *filp);
+extern int	     drm_fasync(int fd, struct file *filp, int on);
+extern ssize_t	     drm_read(struct file *filp, char *buf, size_t count,
+			      loff_t *off);
+extern int	     drm_write_string(drm_device_t *dev, const char *s);
+
+				/* Mapping support (vm.c) */
+extern unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+				   unsigned long address,
+				   int write_access);
+extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+				       unsigned long address,
+				       int write_access);
+extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+				       unsigned long address,
+				       int write_access);
+extern void	     drm_vm_open(struct vm_area_struct *vma);
+extern void	     drm_vm_close(struct vm_area_struct *vma);
+extern int	     drm_mmap_dma(struct file *filp,
+				  struct vm_area_struct *vma);
+extern int	     drm_mmap(struct file *filp, struct vm_area_struct *vma);
+
+
+				/* Proc support (proc.c) */
+extern int	     drm_proc_init(drm_device_t *dev);
+extern int	     drm_proc_cleanup(void);
+
+				/* Memory management support (memory.c) */
+extern void	     drm_mem_init(void);
+extern int	     drm_mem_info(char *buf, char **start, off_t offset,
+				  int len, int *eof, void *data);
+extern void	     *drm_alloc(size_t size, int area);
+extern void	     *drm_realloc(void *oldpt, size_t oldsize, size_t size,
+				  int area);
+extern char	     *drm_strdup(const char *s, int area);
+extern void	     drm_strfree(const char *s, int area);
+extern void	     drm_free(void *pt, size_t size, int area);
+extern unsigned long drm_alloc_pages(int order, int area);
+extern void	     drm_free_pages(unsigned long address, int order,
+				    int area);
+extern void	     *drm_ioremap(unsigned long offset, unsigned long size);
+extern void	     drm_ioremapfree(void *pt, unsigned long size);
+
+				/* Buffer management support (bufs.c) */
+extern int	     drm_order(unsigned long size);
+extern int	     drm_addmap(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_addbufs(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_infobufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_markbufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_freebufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_mapbufs(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+
+
+				/* Buffer list management support (lists.c) */
+extern int	     drm_waitlist_create(drm_waitlist_t *bl, int count);
+extern int	     drm_waitlist_destroy(drm_waitlist_t *bl);
+extern int	     drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf);
+extern drm_buf_t     *drm_waitlist_get(drm_waitlist_t *bl);
+
+extern int	     drm_freelist_create(drm_freelist_t *bl, int count);
+extern int	     drm_freelist_destroy(drm_freelist_t *bl);
+extern int	     drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl,
+				      drm_buf_t *buf);
+extern drm_buf_t     *drm_freelist_get(drm_freelist_t *bl, int block);
+
+				/* DMA support (gen_dma.c) */
+extern void	     drm_dma_setup(drm_device_t *dev);
+extern void	     drm_dma_takedown(drm_device_t *dev);
+extern void	     drm_free_buffer(drm_device_t *dev, drm_buf_t *buf);
+extern void	     drm_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int	     drm_context_switch(drm_device_t *dev, int old, int new);
+extern int	     drm_context_switch_complete(drm_device_t *dev, int new);
+extern void	     drm_wakeup(drm_device_t *dev, drm_buf_t *buf);
+extern void	     drm_clear_next_buffer(drm_device_t *dev);
+extern int	     drm_select_queue(drm_device_t *dev,
+				      void (*wrapper)(unsigned long));
+extern int	     drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma);
+extern int	     drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma);
+#if DRM_DMA_HISTOGRAM
+extern int	     drm_histogram_slot(unsigned long count);
+extern void	     drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf);
+#endif
+
+
+				/* Misc. IOCTL support (ioctl.c) */
+extern int	     drm_irq_busid(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_getunique(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_setunique(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+
+
+				/* Context IOCTL support (context.c) */
+extern int	     drm_resctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_addctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_modctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_getctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_switchctx(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_newctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_rmctx(struct inode *inode, struct file *filp,
+			       unsigned int cmd, unsigned long arg);
+
+
+				/* Drawable IOCTL support (drawable.c) */
+extern int	     drm_adddraw(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_rmdraw(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+
+
+				/* Authentication IOCTL support (auth.c) */
+extern int	     drm_add_magic(drm_device_t *dev, drm_file_t *priv,
+				   drm_magic_t magic);
+extern int	     drm_remove_magic(drm_device_t *dev, drm_magic_t magic);
+extern int	     drm_getmagic(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_authmagic(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+
+
+				/* Locking IOCTL support (lock.c) */
+extern int	     drm_block(struct inode *inode, struct file *filp,
+			       unsigned int cmd, unsigned long arg);
+extern int	     drm_unblock(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_lock_take(__volatile__ unsigned int *lock,
+				   unsigned int context);
+extern int	     drm_lock_transfer(__volatile__ unsigned int *lock,
+				       unsigned int context);
+extern int	     drm_lock_free(drm_device_t *dev,
+				   __volatile__ unsigned int *lock,
+				   unsigned int context);
+extern int	     drm_finish(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_flush_unblock(drm_device_t *dev, int context,
+				       drm_lock_flags_t flags);
+extern int	     drm_flush_block_and_flush(drm_device_t *dev, int context,
+					       drm_lock_flags_t flags);
+#endif
+#endif
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/fops.c linux/drivers/char/drm/fops.c
--- v2.3.17/linux/drivers/char/drm/fops.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/fops.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,204 @@
+/* fops.c -- File operations for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:46 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/fops.c,v 1.3 1999/08/20 15:36:45 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+/* drm_open is called whenever a process opens /dev/drm. */
+
+int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
+{
+	kdev_t	     minor = MINOR(inode->i_rdev);
+	drm_file_t   *priv;
+
+	if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */
+
+	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
+
+	priv		    = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
+	memset(priv, 0, sizeof(*priv));
+	filp->private_data  = priv;
+	priv->uid	    = current->euid;
+	priv->pid	    = current->pid;
+	priv->minor	    = minor;
+	priv->dev	    = dev;
+	priv->ioctl_count   = 0;
+	priv->authenticated = capable(CAP_SYS_ADMIN);
+
+	down(&dev->struct_sem);
+	if (!dev->file_last) {
+		priv->next	= NULL;
+		priv->prev	= NULL;
+		dev->file_first = priv;
+		dev->file_last	= priv;
+	} else {
+		priv->next	     = NULL;
+		priv->prev	     = dev->file_last;
+		dev->file_last->next = priv;
+		dev->file_last	     = priv;
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+int drm_flush(struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d, f_count = %d\n",
+		  current->pid, dev->device, dev->open_count, filp->f_count);
+	return 0;
+}
+
+/* drm_release is called whenever a process closes /dev/drm*.  Linux calls
+   this only if any mappings have been closed. */
+
+int drm_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+
+	drm_reclaim_buffers(dev, priv->pid);
+
+	drm_fasync(-1, filp, 0);
+
+	down(&dev->struct_sem);
+	if (priv->prev) priv->prev->next = priv->next;
+	else		dev->file_first	 = priv->next;
+	if (priv->next) priv->next->prev = priv->prev;
+	else		dev->file_last	 = priv->prev;
+	up(&dev->struct_sem);
+	
+	drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+	
+	return 0;
+}
+
+int drm_fasync(int fd, struct file *filp, int on)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+	int	      retcode;
+	
+	DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
+	retcode = fasync_helper(fd, filp, on, &dev->buf_async);
+	if (retcode < 0) return retcode;
+	return 0;
+}
+
+
+/* The drm_read and drm_write_string code (especially that which manages
+   the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
+   DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
+
+ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+	int	      left;
+	int	      avail;
+	int	      send;
+	int	      cur;
+
+	DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
+	
+	while (dev->buf_rp == dev->buf_wp) {
+		DRM_DEBUG("  sleeping\n");
+		if (filp->f_flags & O_NONBLOCK) {
+			return -EAGAIN;
+		}
+		interruptible_sleep_on(&dev->buf_readers);
+		if (signal_pending(current)) {
+			DRM_DEBUG("  interrupted\n");
+			return -ERESTARTSYS;
+		}
+		DRM_DEBUG("  awake\n");
+	}
+
+	left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+	avail = DRM_BSZ - left;
+	send  = DRM_MIN(avail, count);
+
+	while (send) {
+		if (dev->buf_wp > dev->buf_rp) {
+			cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
+		} else {
+			cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
+		}
+		copy_to_user_ret(buf, dev->buf_rp, cur, -EINVAL);
+		dev->buf_rp += cur;
+		if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
+		send -= cur;
+	}
+	
+	wake_up_interruptible(&dev->buf_writers);
+	return DRM_MIN(avail, count);;
+}
+
+int drm_write_string(drm_device_t *dev, const char *s)
+{
+	int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+	int send   = strlen(s);
+	int count;
+
+	DRM_DEBUG("%d left, %d to send (%p, %p)\n",
+		  left, send, dev->buf_rp, dev->buf_wp);
+	
+	if (left == 1 || dev->buf_wp != dev->buf_rp) {
+		DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
+			  left,
+			  dev->buf_wp,
+			  dev->buf_rp);
+	}
+
+	while (send) {
+		if (dev->buf_wp >= dev->buf_rp) {
+			count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
+			if (count == left) --count; /* Leave a hole */
+		} else {
+			count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
+		}
+		strncpy(dev->buf_wp, s, count);
+		dev->buf_wp += count;
+		if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
+		send -= count;
+	}
+
+	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
+	DRM_DEBUG("waking\n");
+	wake_up_interruptible(&dev->buf_readers);
+	return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/gamma_dma.c linux/drivers/char/drm/gamma_dma.c
--- v2.3.17/linux/drivers/char/drm/gamma_dma.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/gamma_dma.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,802 @@
+/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:45 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_dma.c,v 1.8 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "gamma_drv.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+
+/* WARNING!!! MAGIC NUMBER!!!  The number of regions already added to the
+   kernel must be specified here.  Currently, the number is 2.	This must
+   match the order the X server uses for instantiating register regions ,
+   or must be passed in a new ioctl. */
+#define GAMMA_REG(reg)						   \
+	(2							   \
+	 + ((reg < 0x1000)					   \
+	    ? 0							   \
+	    : ((reg < 0x10000) ? 1 : ((reg < 0x11000) ? 2 : 3))))
+
+#define GAMMA_OFF(reg)						   \
+	((reg < 0x1000)						   \
+	 ? reg							   \
+	 : ((reg < 0x10000)					   \
+	    ? (reg - 0x1000)					   \
+	    : ((reg < 0x11000)					   \
+	       ? (reg - 0x10000)				   \
+	       : (reg - 0x11000))))
+
+#define GAMMA_BASE(reg)	 ((unsigned long)dev->maplist[GAMMA_REG(reg)]->handle)
+#define GAMMA_ADDR(reg)	 (GAMMA_BASE(reg) + GAMMA_OFF(reg))
+#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg)
+#define GAMMA_READ(reg)	 GAMMA_DEREF(reg)
+#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0)
+
+#define GAMMA_BROADCASTMASK    0x9378
+#define GAMMA_COMMANDINTENABLE 0x0c48
+#define GAMMA_DMAADDRESS       0x0028
+#define GAMMA_DMACOUNT	       0x0030
+#define GAMMA_FILTERMODE       0x8c00
+#define GAMMA_GCOMMANDINTFLAGS 0x0c50
+#define GAMMA_GCOMMANDMODE     0x0c40
+#define GAMMA_GCOMMANDSTATUS   0x0c60
+#define GAMMA_GDELAYTIMER      0x0c38
+#define GAMMA_GDMACONTROL      0x0060
+#define GAMMA_GINTENABLE       0x0808
+#define GAMMA_GINTFLAGS	       0x0810
+#define GAMMA_INFIFOSPACE      0x0018
+#define GAMMA_OUTFIFOWORDS     0x0020
+#define GAMMA_OUTPUTFIFO       0x2000
+#define GAMMA_SYNC	       0x8c40
+#define GAMMA_SYNC_TAG	       0x0188
+
+static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
+				      unsigned long length)
+{
+	GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address));
+	while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
+		;
+	GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
+}
+
+static inline void gamma_dma_quiescent(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+	while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
+		;
+	GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
+	GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
+	GAMMA_WRITE(GAMMA_SYNC, 0);
+	
+				/* Read from first MX */
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
+	
+
+				/* Read from second MX */
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
+}
+
+static inline void gamma_dma_ready(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+}
+
+static inline int gamma_dma_is_ready(drm_device_t *dev)
+{
+	return !GAMMA_READ(GAMMA_DMACOUNT);
+}
+
+static void gamma_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+	drm_device_dma_t *dma = dev->dma;
+	
+	atomic_inc(&dev->total_irq);
+	GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
+	GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
+	GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
+	if (gamma_dma_is_ready(dev)) {
+				/* Free previous buffer */
+		if (test_and_set_bit(0, &dev->dma_flag)) {
+			atomic_inc(&dma->total_missed_free);
+			return;
+		}
+		if (dma->this_buffer) {
+			drm_free_buffer(dev, dma->this_buffer);
+			dma->this_buffer = NULL;
+		}
+		clear_bit(0, &dev->dma_flag);
+
+				/* Dispatch new buffer */
+		queue_task(&dev->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
+/* Only called by gamma_dma_schedule. */
+static int gamma_do_dma(drm_device_t *dev, int locked)
+{
+	unsigned long	 address;
+	unsigned long	 length;
+	drm_buf_t	 *buf;
+	int		 retcode = 0;
+	drm_device_dma_t *dma = dev->dma;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	 dma_start, dma_stop;
+#endif
+
+	if (test_and_set_bit(0, &dev->dma_flag)) {
+		atomic_inc(&dma->total_missed_dma);
+		return -EBUSY;
+	}
+	
+#if DRM_DMA_HISTOGRAM
+	dma_start = get_cycles();
+#endif
+
+	if (!dma->next_buffer) {
+		DRM_ERROR("No next_buffer\n");
+		clear_bit(0, &dev->dma_flag);
+		return -EINVAL;
+	}
+
+	buf	= dma->next_buffer;
+	address = (unsigned long)buf->address;
+	length	= buf->used;
+
+	DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
+		  buf->context, buf->idx, length);
+
+	if (buf->list == DRM_LIST_RECLAIM) {
+		drm_clear_next_buffer(dev);
+		drm_free_buffer(dev, buf);
+		clear_bit(0, &dev->dma_flag);
+		return -EINVAL;
+	}
+
+	if (!length) {
+		DRM_ERROR("0 length buffer\n");
+		drm_clear_next_buffer(dev);
+		drm_free_buffer(dev, buf);
+		clear_bit(0, &dev->dma_flag);
+		return 0;
+	}
+	
+	if (!gamma_dma_is_ready(dev)) {
+		clear_bit(0, &dev->dma_flag);
+		return -EBUSY;
+	}
+
+	if (buf->while_locked) {
+		if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+			DRM_ERROR("Dispatching buffer %d from pid %d"
+				  " \"while locked\", but no lock held\n",
+				  buf->idx, buf->pid);
+		}
+	} else {
+		if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock,
+					      DRM_KERNEL_CONTEXT)) {
+			atomic_inc(&dma->total_missed_lock);
+			clear_bit(0, &dev->dma_flag);
+			return -EBUSY;
+		}
+	}
+
+	if (dev->last_context != buf->context
+	    && !(dev->queuelist[buf->context]->flags
+		 & _DRM_CONTEXT_PRESERVED)) {
+				/* PRE: dev->last_context != buf->context */
+		if (drm_context_switch(dev, dev->last_context, buf->context)) {
+			drm_clear_next_buffer(dev);
+			drm_free_buffer(dev, buf);
+		}
+		retcode = -EBUSY;
+		goto cleanup;
+			
+				/* POST: we will wait for the context
+				   switch and will dispatch on a later call
+				   when dev->last_context == buf->context.
+				   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+				   TIME! */
+	}
+
+	drm_clear_next_buffer(dev);
+	buf->pending	 = 1;
+	buf->waiting	 = 0;
+	buf->list	 = DRM_LIST_PEND;
+#if DRM_DMA_HISTOGRAM
+	buf->time_dispatched = get_cycles();
+#endif
+
+	gamma_dma_dispatch(dev, address, length);
+	drm_free_buffer(dev, dma->this_buffer);
+	dma->this_buffer = buf;
+
+	atomic_add(length, &dma->total_bytes);
+	atomic_inc(&dma->total_dmas);
+
+	if (!buf->while_locked && !dev->context_flag && !locked) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+cleanup:
+
+	clear_bit(0, &dev->dma_flag);
+
+#if DRM_DMA_HISTOGRAM
+	dma_stop = get_cycles();
+	atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]);
+#endif
+
+	return retcode;
+}
+
+static void gamma_dma_schedule_timer_wrapper(unsigned long dev)
+{
+	gamma_dma_schedule((drm_device_t *)dev, 0);
+}
+
+static void gamma_dma_schedule_tq_wrapper(void *dev)
+{
+	gamma_dma_schedule(dev, 0);
+}
+
+int gamma_dma_schedule(drm_device_t *dev, int locked)
+{
+	int		 next;
+	drm_queue_t	 *q;
+	drm_buf_t	 *buf;
+	int		 retcode   = 0;
+	int		 processed = 0;
+	int		 missed;
+	int		 expire	   = 20;
+	drm_device_dma_t *dma	   = dev->dma;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	 schedule_start;
+#endif
+
+	if (test_and_set_bit(0, &dev->interrupt_flag)) {
+				/* Not reentrant */
+		atomic_inc(&dma->total_missed_sched);
+		return -EBUSY;
+	}
+	missed = atomic_read(&dma->total_missed_sched);
+
+#if DRM_DMA_HISTOGRAM
+	schedule_start = get_cycles();
+#endif
+
+again:
+	if (dev->context_flag) {
+		clear_bit(0, &dev->interrupt_flag);
+		return -EBUSY;
+	}
+	if (dma->next_buffer) {
+				/* Unsent buffer that was previously
+				   selected, but that couldn't be sent
+				   because the lock could not be obtained
+				   or the DMA engine wasn't ready.  Try
+				   again. */
+		atomic_inc(&dma->total_tried);
+		if (!(retcode = gamma_do_dma(dev, locked))) {
+			atomic_inc(&dma->total_hit);
+			++processed;
+		}
+	} else {
+		do {
+			next = drm_select_queue(dev,
+					     gamma_dma_schedule_timer_wrapper);
+			if (next >= 0) {
+				q   = dev->queuelist[next];
+				buf = drm_waitlist_get(&q->waitlist);
+				dma->next_buffer = buf;
+				dma->next_queue	 = q;
+				if (buf && buf->list == DRM_LIST_RECLAIM) {
+					drm_clear_next_buffer(dev);
+					drm_free_buffer(dev, buf);
+				}
+			}
+		} while (next >= 0 && !dma->next_buffer);
+		if (dma->next_buffer) {
+			if (!(retcode = gamma_do_dma(dev, locked))) {
+				++processed;
+			}
+		}
+	}
+
+	if (--expire) {
+		if (missed != atomic_read(&dma->total_missed_sched)) {
+			atomic_inc(&dma->total_lost);
+			if (gamma_dma_is_ready(dev)) goto again;
+		}
+		if (processed && gamma_dma_is_ready(dev)) {
+			atomic_inc(&dma->total_lost);
+			processed = 0;
+			goto again;
+		}
+	}
+	
+	clear_bit(0, &dev->interrupt_flag);
+	
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles()
+							   - schedule_start)]);
+#endif
+	return retcode;
+}
+
+static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d)
+{
+	unsigned long	  address;
+	unsigned long	  length;
+	int		  must_free = 0;
+	int		  retcode   = 0;
+	int		  i;
+	int		  idx;
+	drm_buf_t	  *buf;
+	drm_buf_t	  *last_buf = NULL;
+	drm_device_dma_t  *dma	    = dev->dma;
+	DECLARE_WAITQUEUE(entry, current);
+
+				/* Turn off interrupt handling */
+	while (test_and_set_bit(0, &dev->interrupt_flag)) {
+		schedule();
+		if (signal_pending(current)) return -EINTR;
+	}
+	if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
+		while (!drm_lock_take(&dev->lock.hw_lock->lock,
+				      DRM_KERNEL_CONTEXT)) {
+			schedule();
+			if (signal_pending(current)) {
+				clear_bit(0, &dev->interrupt_flag);
+				return -EINTR;
+			}
+		}
+		++must_free;
+	}
+	atomic_inc(&dma->total_prio);
+
+	for (i = 0; i < d->send_count; i++) {
+		idx = d->send_indices[i];
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  d->send_indices[i], dma->buf_count - 1);
+			continue;
+		}
+		buf = dma->buflist[ idx ];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d using buffer owned by %d\n",
+				  current->pid, buf->pid);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		if (buf->list != DRM_LIST_NONE) {
+			DRM_ERROR("Process %d using %d's buffer on list %d\n",
+				  current->pid, buf->pid, buf->list);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+				/* This isn't a race condition on
+				   buf->list, since our concern is the
+				   buffer reclaim during the time the
+				   process closes the /dev/drm? handle, so
+				   it can't also be doing DMA. */
+		buf->list	  = DRM_LIST_PRIO;
+		buf->used	  = d->send_sizes[i];
+		buf->context	  = d->context;
+		buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
+		address		  = (unsigned long)buf->address;
+		length		  = buf->used;
+		if (!length) {
+			DRM_ERROR("0 length buffer\n");
+		}
+		if (buf->pending) {
+			DRM_ERROR("Sending pending buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		if (buf->waiting) {
+			DRM_ERROR("Sending waiting buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		buf->pending = 1;
+		
+		if (dev->last_context != buf->context
+		    && !(dev->queuelist[buf->context]->flags
+			 & _DRM_CONTEXT_PRESERVED)) {
+			add_wait_queue(&dev->context_wait, &entry);
+			current->state = TASK_INTERRUPTIBLE;
+				/* PRE: dev->last_context != buf->context */
+			drm_context_switch(dev, dev->last_context,
+					   buf->context);
+				/* POST: we will wait for the context
+				   switch and will dispatch on a later call
+				   when dev->last_context == buf->context.
+				   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+				   TIME! */
+			schedule();
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&dev->context_wait, &entry);
+			if (signal_pending(current)) {
+				retcode = -EINTR;
+				goto cleanup;
+			}
+			if (dev->last_context != buf->context) {
+				DRM_ERROR("Context mismatch: %d %d\n",
+					  dev->last_context,
+					  buf->context);
+			}
+		}
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued     = get_cycles();
+		buf->time_dispatched = buf->time_queued;
+#endif
+		gamma_dma_dispatch(dev, address, length);
+		atomic_add(length, &dma->total_bytes);
+		atomic_inc(&dma->total_dmas);
+		
+		if (last_buf) {
+			drm_free_buffer(dev, last_buf);
+		}
+		last_buf = buf;
+	}
+
+
+cleanup:
+	if (last_buf) {
+		gamma_dma_ready(dev);
+		drm_free_buffer(dev, last_buf);
+	}
+	
+	if (must_free && !dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+	clear_bit(0, &dev->interrupt_flag);
+	return retcode;
+}
+
+static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
+{
+	DECLARE_WAITQUEUE(entry, current);
+	drm_buf_t	  *last_buf = NULL;
+	int		  retcode   = 0;
+	drm_device_dma_t  *dma	    = dev->dma;
+
+	if (d->flags & _DRM_DMA_BLOCK) {
+		last_buf = dma->buflist[d->send_indices[d->send_count-1]];
+		add_wait_queue(&last_buf->dma_wait, &entry);
+	}
+	
+	if ((retcode = drm_dma_enqueue(dev, d))) {
+		if (d->flags & _DRM_DMA_BLOCK)
+			remove_wait_queue(&last_buf->dma_wait, &entry);
+		return retcode;
+	}
+	
+	gamma_dma_schedule(dev, 0);
+	
+	if (d->flags & _DRM_DMA_BLOCK) {
+		DRM_DEBUG("%d waiting\n", current->pid);
+		current->state = TASK_INTERRUPTIBLE;
+		for (;;) {
+			if (!last_buf->waiting
+			    && !last_buf->pending)
+				break; /* finished */
+			schedule();
+			if (signal_pending(current)) {
+				retcode = -EINTR; /* Can't restart */
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		DRM_DEBUG("%d running\n", current->pid);
+		remove_wait_queue(&last_buf->dma_wait, &entry);
+		if (!retcode
+		    || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
+			if (!waitqueue_active(&last_buf->dma_wait)) {
+				drm_free_buffer(dev, last_buf);
+			}
+		}
+		if (retcode) {
+			DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",
+				  d->context,
+				  last_buf->waiting,
+				  last_buf->pending,
+				  DRM_WAITCOUNT(dev, d->context),
+				  last_buf->idx,
+				  last_buf->list,
+				  last_buf->pid,
+				  current->pid);
+		}
+	}
+	return retcode;
+}
+
+int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_device_dma_t  *dma	    = dev->dma;
+	int		  retcode   = 0;
+	drm_dma_t	  d;
+
+	copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
+	DRM_DEBUG("%d %d: %d send, %d req\n",
+		  current->pid, d.context, d.send_count, d.request_count);
+
+	if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) {
+		DRM_ERROR("Process %d using context %d\n",
+			  current->pid, d.context);
+		return -EINVAL;
+	}
+	if (d.send_count < 0 || d.send_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
+			  current->pid, d.send_count, dma->buf_count);
+		return -EINVAL;
+	}
+	if (d.request_count < 0 || d.request_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+			  current->pid, d.request_count, dma->buf_count);
+		return -EINVAL;
+	}
+
+	if (d.send_count) {
+		if (d.flags & _DRM_DMA_PRIORITY)
+			retcode = gamma_dma_priority(dev, &d);
+		else 
+			retcode = gamma_dma_send_buffers(dev, &d);
+	}
+
+	d.granted_count = 0;
+
+	if (!retcode && d.request_count) {
+		retcode = drm_dma_get_buffers(dev, &d);
+	}
+
+	DRM_DEBUG("%d returning, granted = %d\n",
+		  current->pid, d.granted_count);
+	copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+
+	return retcode;
+}
+
+int gamma_irq_install(drm_device_t *dev, int irq)
+{
+	int retcode;
+
+	if (!irq)     return -EINVAL;
+	
+	down(&dev->struct_sem);
+	if (dev->irq) {
+		up(&dev->struct_sem);
+		return -EBUSY;
+	}
+	dev->irq = irq;
+	up(&dev->struct_sem);
+	
+	DRM_DEBUG("%d\n", irq);
+
+	dev->context_flag     = 0;
+	dev->interrupt_flag   = 0;
+	dev->dma_flag	      = 0;
+	
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue  = NULL;
+	dev->dma->this_buffer = NULL;
+
+	dev->tq.next	      = NULL;
+	dev->tq.sync	      = 0;
+	dev->tq.routine	      = gamma_dma_schedule_tq_wrapper;
+	dev->tq.data	      = dev;
+
+
+				/* Before installing handler */
+	GAMMA_WRITE(GAMMA_GCOMMANDMODE, 0);
+	GAMMA_WRITE(GAMMA_GDMACONTROL, 0);
+	
+				/* Install handler */
+	if ((retcode = request_irq(dev->irq,
+				   gamma_dma_service,
+				   0,
+				   dev->devname,
+				   dev))) {
+		down(&dev->struct_sem);
+		dev->irq = 0;
+		up(&dev->struct_sem);
+		return retcode;
+	}
+
+				/* After installing handler */
+	GAMMA_WRITE(GAMMA_GINTENABLE,	    0x2001);
+	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0x0008);
+	GAMMA_WRITE(GAMMA_GDELAYTIMER,	   0x39090);
+	
+	return 0;
+}
+
+int gamma_irq_uninstall(drm_device_t *dev)
+{
+	int irq;
+
+	down(&dev->struct_sem);
+	irq	 = dev->irq;
+	dev->irq = 0;
+	up(&dev->struct_sem);
+	
+	if (!irq) return -EINVAL;
+	
+	DRM_DEBUG("%d\n", irq);
+	
+	GAMMA_WRITE(GAMMA_GDELAYTIMER,	    0);
+	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0);
+	GAMMA_WRITE(GAMMA_GINTENABLE,	    0);
+	free_irq(irq, dev);
+
+	return 0;
+}
+
+
+int gamma_control(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_control_t	ctl;
+	int		retcode;
+	
+	copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
+	
+	switch (ctl.func) {
+	case DRM_INST_HANDLER:
+		if ((retcode = gamma_irq_install(dev, ctl.irq)))
+			return retcode;
+		break;
+	case DRM_UNINST_HANDLER:
+		if ((retcode = gamma_irq_uninstall(dev)))
+			return retcode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_lock_t	  lock;
+	drm_queue_t	  *q;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	  start;
+
+	dev->lck_start = start = get_cycles();
+#endif
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+		  lock.context, current->pid, dev->lock.hw_lock->lock,
+		  lock.flags);
+
+	if (lock.context < 0 || lock.context >= dev->queue_count)
+		return -EINVAL;
+	q = dev->queuelist[lock.context];
+	
+	ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+
+	if (!ret) {
+		if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+		    != lock.context) {
+			long j = jiffies - dev->lock.lock_time;
+
+			if (j > 0 && j <= DRM_LOCK_SLICE) {
+				/* Can't take lock if we just had it and
+				   there is contention. */
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(j);
+			}
+		}
+		add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				ret = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  lock.context)) {
+				dev->lock.pid	    = current->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				atomic_inc(&q->total_locks);
+				break;	/* Got lock */
+			}
+			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	}
+
+	drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */
+	
+	if (!ret) {
+		if (lock.flags & _DRM_LOCK_READY)
+			gamma_dma_ready(dev);
+		if (lock.flags & _DRM_LOCK_QUIESCENT)
+			gamma_dma_quiescent(dev);
+	}
+	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+	
+	return ret;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c
--- v2.3.17/linux/drivers/char/drm/gamma_drv.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/gamma_drv.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,525 @@
+/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.c,v 1.17 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define EXPORT_SYMTAB
+#include "drmP.h"
+#include "gamma_drv.h"
+EXPORT_SYMBOL(gamma_init);
+EXPORT_SYMBOL(gamma_cleanup);
+
+#define GAMMA_NAME	 "gamma"
+#define GAMMA_DESC	 "3dlabs GMX 2000"
+#define GAMMA_DATE	 "19990830"
+#define GAMMA_MAJOR	 0
+#define GAMMA_MINOR	 0
+#define GAMMA_PATCHLEVEL 5
+
+static drm_device_t	      gamma_device;
+
+static struct file_operations gamma_fops = {
+	open:	 gamma_open,
+	flush:	 drm_flush,
+	release: gamma_release,
+	ioctl:	 gamma_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+};
+
+static struct miscdevice      gamma_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  GAMMA_NAME,
+	fops:  &gamma_fops,
+};
+
+static drm_ioctl_desc_t	      gamma_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]    = { gamma_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]  = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]  = { drm_irq_busid,	  0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	     = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]    = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]    = { gamma_control,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]    = { drm_addmap,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]   = { drm_addbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]  = { drm_markbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]  = { drm_infobufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]   = { drm_mapbufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]  = { drm_freebufs,	  1, 0 },
+	
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]    = { drm_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]     = { drm_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]    = { drm_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]    = { drm_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]    = { drm_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]    = { drm_resctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]   = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]    = { drm_rmdraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_DMA)]	     = { gamma_dma,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	     = { gamma_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]     = { gamma_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]     = { drm_finish,	  1, 0 },
+};
+#define GAMMA_IOCTL_COUNT DRM_ARRAY_SIZE(gamma_ioctls)
+
+#ifdef MODULE
+int			      init_module(void);
+void			      cleanup_module(void);
+static char		      *gamma = NULL;
+
+MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas.");
+MODULE_DESCRIPTION("3dlabs GMX 2000");
+MODULE_PARM(gamma, "s");
+
+/* init_module is called when insmod is used to load the module */
+
+int init_module(void)
+{
+	return gamma_init();
+}
+
+/* cleanup_module is called when rmmod is used to unload the module */
+
+void cleanup_module(void)
+{
+	gamma_cleanup();
+}
+#endif
+
+#ifndef MODULE
+/* gamma_setup is called by the kernel to parse command-line options passed
+ * via the boot-loader (e.g., LILO).  It calls the insmod option routine,
+ * drm_parse_drm.
+ *
+ * This is not currently supported, since it requires changes to
+ * linux/init/main.c. */
+ 
+
+void __init gamma_setup(char *str, int *ints)
+{
+	if (ints[0] != 0) {
+		DRM_ERROR("Illegal command line format, ignored\n");
+		return;
+	}
+	drm_parse_options(str);
+}
+#endif
+
+static int gamma_setup(drm_device_t *dev)
+{
+	int i;
+	
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	drm_dma_setup(dev);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+#if DRM_DMA_HISTO
+	memset(&dev->histo, 0, sizeof(dev->histo));
+#endif
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+	
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+			
+	DRM_DEBUG("\n");
+			
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+			
+	return 0;
+}
+
+
+static int gamma_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	if (dev->irq) gamma_irq_uninstall(dev);
+	
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+	
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+	
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+	
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+	
+	if (dev->queuelist) {
+		for (i = 0; i < dev->queue_count; i++) {
+			drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
+			if (dev->queuelist[i]) {
+				drm_free(dev->queuelist[i],
+					 sizeof(*dev->queuelist[0]),
+					 DRM_MEM_QUEUES);
+				dev->queuelist[i] = NULL;
+			}
+		}
+		drm_free(dev->queuelist,
+			 dev->queue_slots * sizeof(*dev->queuelist),
+			 DRM_MEM_QUEUES);
+		dev->queuelist	 = NULL;
+	}
+
+	drm_dma_takedown(dev);
+
+	dev->queue_count     = 0;
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+/* gamma_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+int gamma_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &gamma_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+	
+#ifdef MODULE
+	drm_parse_options(gamma);
+#endif
+
+	if ((retcode = misc_register(&gamma_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", GAMMA_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, gamma_misc.minor);
+	dev->name   = GAMMA_NAME;
+
+	drm_mem_init();
+	drm_proc_init(dev);
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+		 GAMMA_NAME,
+		 GAMMA_MAJOR,
+		 GAMMA_MINOR,
+		 GAMMA_PATCHLEVEL,
+		 GAMMA_DATE,
+		 gamma_misc.minor);
+	
+	return 0;
+}
+
+/* gamma_cleanup is called via cleanup_module at module unload time. */
+
+void gamma_cleanup(void)
+{
+	drm_device_t	      *dev = &gamma_device;
+
+	DRM_DEBUG("\n");
+	
+	drm_proc_cleanup();
+	if (misc_deregister(&gamma_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	gamma_takedown(dev);
+}
+
+int gamma_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	copy_from_user_ret(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version),
+			   -EFAULT);
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		copy_to_user_ret(name, value, len, -EFAULT); \
+	}
+
+	version.version_major	   = GAMMA_MAJOR;
+	version.version_minor	   = GAMMA_MINOR;
+	version.version_patchlevel = GAMMA_PATCHLEVEL;
+
+	DRM_COPY(version.name, GAMMA_NAME);
+	DRM_COPY(version.date, GAMMA_DATE);
+	DRM_COPY(version.desc, GAMMA_DESC);
+
+	copy_to_user_ret((drm_version_t *)arg,
+			 &version,
+			 sizeof(version),
+			 -EFAULT);
+	return 0;
+}
+
+int gamma_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &gamma_device;
+	int	      retcode = 0;
+	
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+		MOD_INC_USE_COUNT;
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return gamma_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+int gamma_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+	int	      retcode = 0;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_release(inode, filp))) {
+		MOD_DEC_USE_COUNT;
+		atomic_inc(&dev->total_close);
+		spin_lock(&dev->count_lock);
+		if (!--dev->open_count) {
+			if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+				DRM_ERROR("Device busy: %d %d\n",
+					  atomic_read(&dev->ioctl_count),
+					  dev->blocked);
+				spin_unlock(&dev->count_lock);
+				return -EBUSY;
+			}
+			spin_unlock(&dev->count_lock);
+			return gamma_takedown(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int gamma_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+	
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= GAMMA_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &gamma_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+	
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+
+int gamma_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+	
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+	drm_lock_transfer(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+	gamma_dma_schedule(dev, 1);
+	if (!dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
+						       - dev->lck_start)]);
+#endif
+	
+	return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/gamma_drv.h linux/drivers/char/drm/gamma_drv.h
--- v2.3.17/linux/drivers/char/drm/gamma_drv.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/gamma_drv.h	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,58 @@
+/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:24:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/gamma_drv.h,v 1.4 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ * 
+ */
+
+#ifndef _GAMMA_DRV_H_
+#define _GAMMA_DRV_H_
+
+				/* gamma_drv.c */
+extern int  gamma_init(void);
+extern void gamma_cleanup(void);
+extern int  gamma_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  gamma_open(struct inode *inode, struct file *filp);
+extern int  gamma_release(struct inode *inode, struct file *filp);
+extern int  gamma_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  gamma_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  gamma_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* gamma_dma.c */
+extern int  gamma_dma_schedule(drm_device_t *dev, int locked);
+extern int  gamma_dma(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+extern int  gamma_irq_install(drm_device_t *dev, int irq);
+extern int  gamma_irq_uninstall(drm_device_t *dev);
+extern int  gamma_control(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+
+#endif
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/init.c linux/drivers/char/drm/init.c
--- v2.3.17/linux/drivers/char/drm/init.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/init.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,99 @@
+/* init.c -- Setup/Cleanup for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/init.c,v 1.3 1999/08/20 15:07:01 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int			      drm_flags		= 0;
+
+/* drm_parse_option parses a single option.  See description for
+   drm_parse_drm for details. */
+
+static void drm_parse_option(char *s)
+{
+	char *c, *r;
+	
+	DRM_DEBUG("\"%s\"\n", s);
+	if (!s || !*s) return;
+	for (c = s; *c && *c != ':'; c++); /* find : or \0 */
+	if (*c) r = c + 1; else r = NULL;  /* remember remainder */
+	*c = '\0';			   /* terminate */
+	if (!strcmp(s, "noctx")) {
+		drm_flags |= DRM_FLAG_NOCTX;
+		DRM_INFO("Server-mediated context switching OFF\n");
+		return;
+	}
+	if (!strcmp(s, "debug")) {
+		drm_flags |= DRM_FLAG_DEBUG;
+		DRM_INFO("Debug messages ON\n");
+		return;
+	}
+	DRM_ERROR("\"%s\" is not a valid option\n", s);
+	return;
+}
+
+/* drm_parse_options parse the insmod "drm=" options, or the command-line
+ * options passed to the kernel via LILO.  The grammar of the format is as
+ * follows:
+ *
+ * drm		::= 'drm=' option_list
+ * option_list	::= option [ ';' option_list ]
+ * option	::= 'device:' major
+ *		|   'debug' 
+ *		|   'noctx'
+ * major	::= INTEGER
+ *
+ * Note that 's' contains option_list without the 'drm=' part.
+ *
+ * device=major,minor specifies the device number used for /dev/drm
+ *	  if major == 0 then the misc device is used
+ *	  if major == 0 and minor == 0 then dynamic misc allocation is used
+ * debug=on specifies that debugging messages will be printk'd
+ * debug=trace specifies that each function call will be logged via printk
+ * debug=off turns off all debugging options
+ *
+ */
+
+void drm_parse_options(char *s)
+{
+	char *h, *t, *n;
+	
+	DRM_DEBUG("\"%s\"\n", s ?: "");
+	if (!s || !*s) return;
+
+	for (h = t = n = s; h && *h; h = n) {
+		for (; *t && *t != ';'; t++);	       /* find ; or \0 */
+		if (*t) n = t + 1; else n = NULL;      /* remember next */
+		*t = '\0';			       /* terminate */
+		drm_parse_option(h);		       /* parse */
+	}
+}
+
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/ioctl.c linux/drivers/char/drm/ioctl.c
--- v2.3.17/linux/drivers/char/drm/ioctl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/ioctl.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,91 @@
+/* ioctl.c -- IOCTL processing for DRM -*- linux-c -*-
+ * Created: Fri Jan  8 09:01:26 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:02 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/ioctl.c,v 1.3 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_irq_busid(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_irq_busid_t p;
+	struct pci_dev	*dev;
+
+	copy_from_user_ret(&p, (drm_irq_busid_t *)arg, sizeof(p), -EFAULT);
+	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
+	if (dev) p.irq = dev->irq;
+	else	 p.irq = 0;
+	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+		  p.busnum, p.devnum, p.funcnum, p.irq);
+	copy_to_user_ret((drm_irq_busid_t *)arg, &p, sizeof(p), -EFAULT);
+	return 0;
+}
+
+int drm_getunique(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_unique_t	 u;
+
+	copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
+	if (u.unique_len >= dev->unique_len) {
+		copy_to_user_ret(u.unique, dev->unique, dev->unique_len,
+				 -EFAULT);
+	}
+	u.unique_len = dev->unique_len;
+	copy_to_user_ret((drm_unique_t *)arg, &u, sizeof(u), -EFAULT);
+	return 0;
+}
+
+int drm_setunique(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_unique_t	 u;
+
+	if (dev->unique_len || dev->unique) return -EBUSY;
+
+	copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
+	if (!u.unique_len) return -EINVAL;
+	
+	dev->unique_len = u.unique_len;
+	dev->unique	= drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+	copy_from_user_ret(dev->unique, u.unique, dev->unique_len,
+			   -EFAULT);
+	dev->unique[dev->unique_len] = '\0';
+
+	dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2,
+				 DRM_MEM_DRIVER);
+	sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
+
+	return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/lists.c linux/drivers/char/drm/lists.c
--- v2.3.17/linux/drivers/char/drm/lists.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/lists.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,252 @@
+/* lists.c -- Buffer list handling routines -*- linux-c -*-
+ * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lists.c,v 1.3 1999/08/20 15:07:02 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_waitlist_create(drm_waitlist_t *bl, int count)
+{
+	DRM_DEBUG("%d\n", count);
+	if (bl->count) return -EINVAL;
+	
+	bl->count      = count;
+	bl->bufs       = drm_alloc((bl->count + 2) * sizeof(*bl->bufs),
+				   DRM_MEM_BUFLISTS);
+	bl->rp	       = bl->bufs;
+	bl->wp	       = bl->bufs;
+	bl->end	       = &bl->bufs[bl->count+1];
+	bl->write_lock = SPIN_LOCK_UNLOCKED;
+	bl->read_lock  = SPIN_LOCK_UNLOCKED;
+	return 0;
+}
+
+int drm_waitlist_destroy(drm_waitlist_t *bl)
+{
+	DRM_DEBUG("\n");
+	if (bl->rp != bl->wp) return -EINVAL;
+	if (bl->bufs) drm_free(bl->bufs,
+			       (bl->count + 2) * sizeof(*bl->bufs),
+			       DRM_MEM_BUFLISTS);
+	bl->count = 0;
+	bl->bufs  = NULL;
+	bl->rp	  = NULL;
+	bl->wp	  = NULL;
+	bl->end	  = NULL;
+	return 0;
+}
+
+int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf)
+{							
+	int	      left;
+	unsigned long flags;
+
+	left = DRM_LEFTCOUNT(bl);
+	DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n",
+		  buf->idx, left, bl->rp, bl->wp);
+	if (!left) {
+		DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
+			  buf->idx, buf->pid);
+		return -EINVAL;
+	}
+#if DRM_DMA_HISTOGRAM
+	buf->time_queued = get_cycles();
+#endif
+	buf->list	 = DRM_LIST_WAIT;
+	
+	spin_lock_irqsave(&bl->write_lock, flags);
+	*bl->wp = buf;
+	if (++bl->wp >= bl->end) bl->wp = bl->bufs;
+	spin_unlock_irqrestore(&bl->write_lock, flags);
+	
+	return 0;
+}
+
+drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl)
+{
+	drm_buf_t     *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bl->read_lock, flags);
+	buf = *bl->rp;
+	if (bl->rp == bl->wp) {
+		spin_unlock_irqrestore(&bl->read_lock, flags);
+		return NULL;
+	}				     
+	if (++bl->rp >= bl->end) bl->rp = bl->bufs;
+	spin_unlock_irqrestore(&bl->read_lock, flags);
+	
+	DRM_DEBUG("get %d\n", buf->idx);
+	return buf;
+}
+
+int drm_freelist_create(drm_freelist_t *bl, int count)
+{
+	DRM_DEBUG("\n");
+	atomic_set(&bl->count, 0);
+	bl->next      = NULL;
+	init_waitqueue_head(&bl->waiting);
+	bl->low_mark  = 0;
+	bl->high_mark = 0;
+	atomic_set(&bl->wfh,   0);
+	++bl->initialized;
+	return 0;
+}
+
+int drm_freelist_destroy(drm_freelist_t *bl)
+{
+	DRM_DEBUG("\n");
+	atomic_set(&bl->count, 0);
+	bl->next = NULL;
+	return 0;
+}
+
+int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
+{
+	unsigned int	 old;
+	unsigned int	 new;
+	char		 failed;
+	int		 count = 0;
+	drm_device_dma_t *dma = dev->dma;
+
+	if (!dma) {
+		DRM_ERROR("No DMA support\n");
+		return 1;
+	}
+
+	if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
+		DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
+			  buf->idx, buf->waiting, buf->pending, buf->list);
+	}
+	DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+		  buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+		  buf->waiting, buf->pending);
+	if (!bl) return 1;
+#if DRM_DMA_HISTOGRAM
+	buf->time_freed = get_cycles();
+	drm_histogram_compute(dev, buf);
+#endif
+	buf->list	= DRM_LIST_FREE;
+	do {
+		old	  = (unsigned long)bl->next;
+		buf->next = (void *)old;
+		new	  = (unsigned long)buf;
+		_DRM_CAS(&bl->next, old, new, failed);
+		if (++count > DRM_LOOPING_LIMIT) {
+			DRM_ERROR("Looping\n");
+			return 1;
+		}
+	} while (failed);
+	atomic_inc(&bl->count);
+	if (atomic_read(&bl->count) > dma->buf_count) {
+		DRM_ERROR("%d of %d buffers free after addition of %d\n",
+			  atomic_read(&bl->count), dma->buf_count, buf->idx);
+		return 1;
+	}
+				/* Check for high water mark */
+	if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
+		atomic_set(&bl->wfh, 0);
+		wake_up_interruptible(&bl->waiting);
+	}
+	return 0;
+}
+
+static drm_buf_t *drm_freelist_try(drm_freelist_t *bl)
+{
+	unsigned int	  old;
+	unsigned int	  new;
+	char		  failed;
+	drm_buf_t	  *buf;
+	int		  count = 0;
+
+	if (!bl) return NULL;
+	
+				/* Get buffer */
+	do {
+		old = (unsigned int)bl->next;
+		if (!old) {
+			return NULL;
+		}
+		new = (unsigned long)bl->next->next;
+		_DRM_CAS(&bl->next, old, new, failed);
+		if (++count > DRM_LOOPING_LIMIT) {
+			DRM_ERROR("Looping\n");
+			return NULL;
+		}
+	} while (failed);
+	atomic_dec(&bl->count);
+	
+	buf	  = (drm_buf_t *)old;
+	buf->next = NULL;
+	buf->list = DRM_LIST_NONE;
+	DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+		  buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+		  buf->waiting, buf->pending);
+	if (buf->waiting || buf->pending) {
+		DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
+			  buf->idx, buf->waiting, buf->pending, buf->list);
+	}
+	
+	return buf;
+}
+
+drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block)
+{
+	drm_buf_t	  *buf	= NULL;
+	DECLARE_WAITQUEUE(entry, current);
+
+	if (!bl || !bl->initialized) return NULL;
+	
+				/* Check for low water mark */
+	if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
+		atomic_set(&bl->wfh, 1);
+	if (atomic_read(&bl->wfh)) {
+		DRM_DEBUG("Block = %d, count = %d, wfh = %d\n",
+			  block, atomic_read(&bl->count),
+			  atomic_read(&bl->wfh));
+		if (block) {
+			add_wait_queue(&bl->waiting, &entry);
+			current->state = TASK_INTERRUPTIBLE;
+			for (;;) {
+				if (!atomic_read(&bl->wfh)
+				    && (buf = drm_freelist_try(bl))) break;
+				schedule();
+				if (signal_pending(current)) break;
+			}
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&bl->waiting, &entry);
+		}
+		return buf;
+	}
+		
+	DRM_DEBUG("Count = %d, wfh = %d\n",
+		  atomic_read(&bl->count), atomic_read(&bl->wfh));
+	return drm_freelist_try(bl);
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/lock.c linux/drivers/char/drm/lock.c
--- v2.3.17/linux/drivers/char/drm/lock.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/lock.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,227 @@
+/* lock.c -- IOCTLs for locking -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lock.c,v 1.5 1999/08/30 13:05:00 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_block(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	DRM_DEBUG("\n");
+	return 0;
+}
+
+int drm_unblock(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	DRM_DEBUG("\n");
+	return 0;
+}
+
+int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old;
+	unsigned int new;
+	char	     failed;
+
+	DRM_DEBUG("%d attempts\n", context);
+	do {
+		old = *lock;
+		if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
+		else			  new = context | _DRM_LOCK_HELD;
+		_DRM_CAS(lock, old, new, failed);
+	} while (failed);
+	if (_DRM_LOCKING_CONTEXT(old) == context) {
+		if (old & _DRM_LOCK_HELD) {
+			if (context != DRM_KERNEL_CONTEXT) {
+				DRM_ERROR("%d holds heavyweight lock\n",
+					  context);
+			}
+			return 0;
+		}
+	}
+	if (new == (context | _DRM_LOCK_HELD)) {
+				/* Have lock */
+		DRM_DEBUG("%d\n", context);
+		return 1;
+	}
+	DRM_DEBUG("%d unable to get lock held by %d\n",
+		  context, _DRM_LOCKING_CONTEXT(old));
+	return 0;
+}
+
+/* This takes a lock forcibly and hands it to context.	Should ONLY be used
+   inside *_unlock to give lock to kernel before calling *_dma_schedule. */
+int drm_lock_transfer(__volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old;
+	unsigned int new;
+	char	     failed;
+
+	do {
+		old = *lock;
+		new = context | _DRM_LOCK_HELD;
+		_DRM_CAS(lock, old, new, failed);
+	} while (failed);
+	DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context);
+	return 1;
+}
+
+int drm_lock_free(drm_device_t *dev,
+		  __volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old;
+	unsigned int new;
+	char	     failed;
+
+	DRM_DEBUG("%d\n", context);
+	do {
+		old = *lock;
+		new = 0;
+		_DRM_CAS(lock, old, new, failed);
+	} while (failed);
+	if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+		DRM_ERROR("%d freed heavyweight lock held by %d\n",
+			  context,
+			  _DRM_LOCKING_CONTEXT(old));
+		return 1;
+	}
+	dev->lock.pid = 0;
+	wake_up_interruptible(&dev->lock.lock_queue);
+	return 0;
+}
+
+static int drm_flush_queue(drm_device_t *dev, int context)
+{
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_queue_t	  *q	= dev->queuelist[context];
+	
+	DRM_DEBUG("\n");
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) > 1) {
+		atomic_inc(&q->block_write);
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&q->flush_queue, &entry);
+		atomic_inc(&q->block_count);
+		for (;;) {
+			if (!DRM_BUFCOUNT(&q->waitlist)) break;
+			schedule();
+			if (signal_pending(current)) {
+				ret = -EINTR; /* Can't restart */
+				break;
+			}
+		}
+		atomic_dec(&q->block_count);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&q->flush_queue, &entry);
+	}
+	atomic_dec(&q->use_count);
+	atomic_inc(&q->total_flushed);
+		
+				/* NOTE: block_write is still incremented!
+				   Use drm_flush_unlock_queue to decrement. */
+	return ret;
+}
+
+static int drm_flush_unblock_queue(drm_device_t *dev, int context)
+{
+	drm_queue_t	  *q	= dev->queuelist[context];
+	
+	DRM_DEBUG("\n");
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) > 1) {
+		if (atomic_read(&q->block_write)) {
+			atomic_dec(&q->block_write);
+			wake_up_interruptible(&q->write_queue);
+		}
+	}
+	atomic_dec(&q->use_count);
+	return 0;
+}
+
+int drm_flush_block_and_flush(drm_device_t *dev, int context,
+			      drm_lock_flags_t flags)
+{
+	int ret = 0;
+	int i;
+	
+	DRM_DEBUG("\n");
+	
+	if (flags & _DRM_LOCK_FLUSH) {
+		ret = drm_flush_queue(dev, DRM_KERNEL_CONTEXT);
+		if (!ret) ret = drm_flush_queue(dev, context);
+	}
+	if (flags & _DRM_LOCK_FLUSH_ALL) {
+		for (i = 0; !ret && i < dev->queue_count; i++) {
+			ret = drm_flush_queue(dev, i);
+		}
+	}
+	return ret;
+}
+
+int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags)
+{
+	int ret = 0;
+	int i;
+	
+	DRM_DEBUG("\n");
+	
+	if (flags & _DRM_LOCK_FLUSH) {
+		ret = drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT);
+		if (!ret) ret = drm_flush_unblock_queue(dev, context);
+	}
+	if (flags & _DRM_LOCK_FLUSH_ALL) {
+		for (i = 0; !ret && i < dev->queue_count; i++) {
+			ret = drm_flush_unblock_queue(dev, i);
+		}
+	}
+		
+	return ret;
+}
+
+int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	int		  ret	  = 0;
+	drm_lock_t	  lock;
+
+	DRM_DEBUG("\n");
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+	ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+	drm_flush_unblock(dev, lock.context, lock.flags);
+	return ret;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/memory.c linux/drivers/char/drm/memory.c
--- v2.3.17/linux/drivers/char/drm/memory.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/memory.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,320 @@
+/* memory.c -- Memory management wrappers for DRM -*- linux-c -*-
+ * Created: Thu Feb  4 14:00:34 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 13:04:33 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/memory.c,v 1.4 1999/08/20 20:00:53 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+typedef struct drm_mem_stats {
+	const char	  *name;
+	int		  succeed_count;
+	int		  free_count;
+	int		  fail_count;
+	unsigned long	  bytes_allocated;
+	unsigned long	  bytes_freed;
+} drm_mem_stats_t;
+
+static spinlock_t	  drm_mem_lock	    = SPIN_LOCK_UNLOCKED;
+static unsigned long	  drm_ram_available = 0;
+static unsigned long	  drm_ram_used	    = 0;
+static drm_mem_stats_t	  drm_mem_stats[]   = {
+	[DRM_MEM_DMA]	   = { "dmabufs"  },
+	[DRM_MEM_SAREA]	   = { "sareas"	  },
+	[DRM_MEM_DRIVER]   = { "driver"	  },
+	[DRM_MEM_MAGIC]	   = { "magic"	  },
+	[DRM_MEM_IOCTLS]   = { "ioctltab" },
+	[DRM_MEM_MAPS]	   = { "maplist"  },
+	[DRM_MEM_VMAS]	   = { "vmalist"  },
+	[DRM_MEM_BUFS]	   = { "buflist"  },
+	[DRM_MEM_SEGS]	   = { "seglist"  },
+	[DRM_MEM_PAGES]	   = { "pagelist" },
+	[DRM_MEM_FILES]	   = { "files"	  },
+	[DRM_MEM_QUEUES]   = { "queues"	  },
+	[DRM_MEM_CMDS]	   = { "commands" },
+	[DRM_MEM_MAPPINGS] = { "mappings" },
+	[DRM_MEM_BUFLISTS] = { "buflists" },
+	{ NULL, 0, }		/* Last entry must be null */
+};
+
+void drm_mem_init(void)
+{
+	drm_mem_stats_t *mem;
+	struct sysinfo	si;
+	
+	for (mem = drm_mem_stats; mem->name; ++mem) {
+		mem->succeed_count   = 0;
+		mem->free_count	     = 0;
+		mem->fail_count	     = 0;
+		mem->bytes_allocated = 0;
+		mem->bytes_freed     = 0;
+	}
+	
+	si_meminfo(&si);
+	drm_ram_available = si.totalram;
+	drm_ram_used	  = 0;
+}
+
+/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
+
+static int _drm_mem_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_mem_stats_t *pt;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("		  total counts			"
+		       " |    outstanding  \n");
+	DRM_PROC_PRINT("type	   alloc freed fail	bytes	   freed"
+		       " | allocs      bytes\n\n");
+	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu	    |\n",
+		       "system", 0, 0, 0, drm_ram_available);
+	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu	    |\n",
+		       "locked", 0, 0, 0, drm_ram_used);
+	DRM_PROC_PRINT("\n");
+	for (pt = drm_mem_stats; pt->name; pt++) {
+		DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
+			       pt->name,
+			       pt->succeed_count,
+			       pt->free_count,
+			       pt->fail_count,
+			       pt->bytes_allocated,
+			       pt->bytes_freed,
+			       pt->succeed_count - pt->free_count,
+			       (long)pt->bytes_allocated
+			       - (long)pt->bytes_freed);
+	}
+	
+	return len;
+}
+
+int drm_mem_info(char *buf, char **start, off_t offset, int len,
+		 int *eof, void *data)
+{
+	int ret;
+	
+	spin_lock(&drm_mem_lock);
+	ret = _drm_mem_info(buf, start, offset, len, eof, data);
+	spin_unlock(&drm_mem_lock);
+	return ret;
+}
+
+void *drm_alloc(size_t size, int area)
+{
+	void *pt;
+	
+	if (!size) {
+		DRM_MEM_ERROR(area, "Allocating 0 bytes\n");
+		return NULL;
+	}
+	
+	if (!(pt = kmalloc(size, GFP_KERNEL))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[area].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return NULL;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_allocated += size;
+	spin_unlock(&drm_mem_lock);
+	return pt;
+}
+
+void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
+{
+	void *pt;
+	
+	if (!(pt = drm_alloc(size, area))) return NULL;
+	if (oldpt && oldsize) {
+		memcpy(pt, oldpt, oldsize);
+		drm_free(oldpt, oldsize, area);
+	}
+	return pt;
+}
+
+char *drm_strdup(const char *s, int area)
+{
+	char *pt;
+	int	 length = s ? strlen(s) : 0;
+	
+	if (!(pt = drm_alloc(length+1, area))) return NULL;
+	strcpy(pt, s);
+	return pt;
+}
+
+void drm_strfree(const char *s, int area)
+{
+	unsigned int size;
+	
+	if (!s) return;
+	
+	size = 1 + (s ? strlen(s) : 0);
+	drm_free((void *)s, size, area);
+}
+
+void drm_free(void *pt, size_t size, int area)
+{
+	int alloc_count;
+	int free_count;
+	
+	if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n");
+	else	 kfree_s(pt, size);
+	spin_lock(&drm_mem_lock);
+	drm_mem_stats[area].bytes_freed += size;
+	free_count  = ++drm_mem_stats[area].free_count;
+	alloc_count =	drm_mem_stats[area].succeed_count;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+unsigned long drm_alloc_pages(int order, int area)
+{
+	unsigned long address;
+	unsigned long bytes	  = PAGE_SIZE << order;
+	unsigned long addr;
+	unsigned int  sz;
+	
+	spin_lock(&drm_mem_lock);
+	if (drm_ram_used > +(DRM_RAM_PERCENT * drm_ram_available) / 100) {
+		spin_unlock(&drm_mem_lock);
+		return 0;
+	}
+	spin_unlock(&drm_mem_lock);
+	
+	address = __get_free_pages(GFP_KERNEL, order);
+	if (!address) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[area].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return 0;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_allocated += bytes;
+	drm_ram_used		            += bytes;
+	spin_unlock(&drm_mem_lock);
+	
+	
+				/* Zero outside the lock */
+	memset((void *)address, 0, bytes);
+	
+				/* Reserve */
+	for (addr = address, sz = bytes;
+	     sz > 0;
+	     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+		mem_map_reserve(MAP_NR(addr));
+	}
+	
+	return address;
+}
+
+void drm_free_pages(unsigned long address, int order, int area)
+{
+	unsigned long bytes = PAGE_SIZE << order;
+	int		  alloc_count;
+	int		  free_count;
+	unsigned long addr;
+	unsigned int  sz;
+	
+	if (!address) {
+		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
+	} else {
+				/* Unreserve */
+		for (addr = address, sz = bytes;
+		     sz > 0;
+		     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+			mem_map_unreserve(MAP_NR(addr));
+		}
+		free_pages(address, order);
+	}
+	
+	spin_lock(&drm_mem_lock);
+	free_count  = ++drm_mem_stats[area].free_count;
+	alloc_count =	drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_freed += bytes;
+	drm_ram_used			-= bytes;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(area,
+			      "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+void *drm_ioremap(unsigned long offset, unsigned long size)
+{
+	void *pt;
+	
+	if (!size) {
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Mapping 0 bytes at 0x%08lx\n", offset);
+		return NULL;
+	}
+	
+	if (!(pt = ioremap(offset, size))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return NULL;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
+	spin_unlock(&drm_mem_lock);
+	return pt;
+}
+
+void drm_ioremapfree(void *pt, unsigned long size)
+{
+	int alloc_count;
+	int free_count;
+	
+	if (!pt)
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Attempt to free NULL pointer\n");
+	else
+		iounmap(pt);
+	
+	spin_lock(&drm_mem_lock);
+	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
+	free_count  = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
+	alloc_count =	drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/proc.c linux/drivers/char/drm/proc.c
--- v2.3.17/linux/drivers/char/drm/proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/proc.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,568 @@
+/* proc.c -- /proc support for DRM -*- linux-c -*-
+ * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 11:31:48 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/proc.c,v 1.4 1999/08/20 15:36:46 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static struct proc_dir_entry *drm_root	   = NULL;
+static struct proc_dir_entry *drm_dev_root = NULL;
+static char		     drm_slot_name[64];
+
+static int	   drm_name_info(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data);
+static int	   drm_vm_info(char *buf, char **start, off_t offset,
+			       int len, int *eof, void *data);
+static int	   drm_clients_info(char *buf, char **start, off_t offset,
+				    int len, int *eof, void *data);
+static int	   drm_queues_info(char *buf, char **start, off_t offset,
+				   int len, int *eof, void *data);
+static int	   drm_bufs_info(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data);
+#if DRM_DEBUG_CODE
+static int	   drm_vma_info(char *buf, char **start, off_t offset,
+				int len, int *eof, void *data);
+#endif
+#if DRM_DMA_HISTOGRAM
+static int	   drm_histo_info(char *buf, char **start, off_t offset,
+				  int len, int *eof, void *data);
+#endif
+
+struct drm_proc_list {
+	const char *name;
+	int	   (*f)(char *, char **, off_t, int, int *, void *);
+} drm_proc_list[] = {
+	{ "name",    drm_name_info    },
+	{ "mem",     drm_mem_info     },
+	{ "vm",	     drm_vm_info      },
+	{ "clients", drm_clients_info },
+	{ "queues",  drm_queues_info  },
+	{ "bufs",    drm_bufs_info    },
+#if DRM_DEBUG_CODE
+	{ "vma",     drm_vma_info     },
+#endif
+#if DRM_DMA_HISTOGRAM
+	{ "histo",   drm_histo_info   },
+#endif
+};
+#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+
+int drm_proc_init(drm_device_t *dev)
+{
+	struct proc_dir_entry *ent;
+	int		      i, j;
+
+	drm_root = create_proc_entry("video", S_IFDIR, NULL);
+	if (!drm_root) {
+		DRM_ERROR("Cannot create /proc/video\n");
+		return -1;
+	}
+
+				/* Instead of doing this search, we should
+				   add some global support for /proc/video. */
+	for (i = 0; i < 8; i++) {
+		sprintf(drm_slot_name, "video/%d", i);
+		drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL);
+		if (!drm_dev_root) {
+			DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
+			remove_proc_entry("video", NULL);
+		}
+		if (drm_dev_root->nlink == 2) break;
+		drm_dev_root = NULL;
+	}
+	if (!drm_dev_root) {
+		DRM_ERROR("Cannot find slot in /proc/video\n");
+		return -1;
+	}
+
+	for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+		ent = create_proc_entry(drm_proc_list[i].name,
+					S_IFREG|S_IRUGO, drm_dev_root);
+		if (!ent) {
+			DRM_ERROR("Cannot create /proc/%s/%s\n",
+				  drm_slot_name, drm_proc_list[i].name);
+			for (j = 0; j < i; j++)
+				remove_proc_entry(drm_proc_list[i].name,
+						  drm_dev_root);
+			remove_proc_entry(drm_slot_name, NULL);
+			remove_proc_entry("video", NULL);
+			return -1;
+		}
+		ent->read_proc = drm_proc_list[i].f;
+		ent->data      = dev;
+	}
+
+	return 0;
+}
+
+
+int drm_proc_cleanup(void)
+{
+	int i;
+	
+	if (drm_root) {
+		if (drm_dev_root) {
+			for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+				remove_proc_entry(drm_proc_list[i].name,
+						  drm_dev_root);
+			}
+			remove_proc_entry(drm_slot_name, NULL);
+		}
+		remove_proc_entry("video", NULL);
+		remove_proc_entry(DRM_NAME, NULL);
+	}
+	drm_root = drm_dev_root = NULL;
+	return 0;
+}
+
+static int drm_name_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+
+	if (dev->unique) {
+		DRM_PROC_PRINT("%s 0x%x %s\n",
+			       dev->name, dev->device, dev->unique);
+	} else {
+		DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
+	}
+	return len;
+}
+
+static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
+			int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	drm_map_t    *map;
+	const char   *types[] = { "FB", "REG", "SHM" };
+	const char   *type;
+	int	     i;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("slot	 offset	      size type flags	 "
+		       "address mtrr\n\n");
+	for (i = 0; i < dev->map_count; i++) {
+		map = dev->maplist[i];
+		if (map->type < 0 || map->type > 2) type = "??";
+		else				    type = types[map->type];
+		DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
+			       i,
+			       map->offset,
+			       map->size,
+			       type,
+			       map->flags,
+			       (unsigned long)map->handle);
+		if (map->mtrr < 0) {
+			DRM_PROC_PRINT("none\n");
+		} else {
+			DRM_PROC_PRINT("%4d\n", map->mtrr);
+		}
+	}
+
+	return len;
+}
+
+static int drm_vm_info(char *buf, char **start, off_t offset, int len,
+		       int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_vm_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+
+static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
+			    int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     i;
+	drm_queue_t  *q;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("  ctx/flags   use   fin"
+		       "   blk/rw/rwf  wait    flushed	   queued"
+		       "      locks\n\n");
+	for (i = 0; i < dev->queue_count; i++) {
+		q = dev->queuelist[i];
+		atomic_inc(&q->use_count);
+		DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
+				   "%5d/0x%03x %5d %5d"
+				   " %5d/%c%c/%c%c%c %5d %10d %10d %10d\n",
+				   i,
+				   q->flags,
+				   atomic_read(&q->use_count),
+				   atomic_read(&q->finalization),
+				   atomic_read(&q->block_count),
+				   atomic_read(&q->block_read) ? 'r' : '-',
+				   atomic_read(&q->block_write) ? 'w' : '-',
+				   waitqueue_active(&q->read_queue) ? 'r':'-',
+				   waitqueue_active(&q->write_queue) ? 'w':'-',
+				   waitqueue_active(&q->flush_queue) ? 'f':'-',
+				   DRM_BUFCOUNT(&q->waitlist),
+				   atomic_read(&q->total_flushed),
+				   atomic_read(&q->total_queued),
+				   atomic_read(&q->total_locks));
+		atomic_dec(&q->use_count);
+	}
+	
+	return len;
+}
+
+static int drm_queues_info(char *buf, char **start, off_t offset, int len,
+			   int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_queues_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+/* drm_bufs_info is called whenever a process reads
+   /dev/drm/<dev>/bufs. */
+
+static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
+			  int *eof, void *data)
+{
+	drm_device_t	 *dev = (drm_device_t *)data;
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma)	return 0;
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT(" o     size count  free	 segs pages    kB\n\n");
+	for (i = 0; i <= DRM_MAX_ORDER; i++) {
+		if (dma->bufs[i].buf_count)
+			DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
+				       i,
+				       dma->bufs[i].buf_size,
+				       dma->bufs[i].buf_count,
+				       atomic_read(&dma->bufs[i]
+						   .freelist.count),
+				       dma->bufs[i].seg_count,
+				       dma->bufs[i].seg_count
+				       *(1 << dma->bufs[i].page_order),
+				       (dma->bufs[i].seg_count
+					* (1 << dma->bufs[i].page_order))
+				       * PAGE_SIZE / 1024);
+	}
+	DRM_PROC_PRINT("\n");
+	for (i = 0; i < dma->buf_count; i++) {
+		if (i && !(i%32)) DRM_PROC_PRINT("\n");
+		DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
+	}
+	DRM_PROC_PRINT("\n");
+
+	return len;
+}
+
+static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_bufs_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+
+static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
+			     int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	drm_file_t   *priv;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("a dev	pid    uid	magic	  ioctls\n\n");
+	for (priv = dev->file_first; priv; priv = priv->next) {
+		DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
+			       priv->authenticated ? 'y' : 'n',
+			       priv->minor,
+			       priv->pid,
+			       priv->uid,
+			       priv->magic,
+			       priv->ioctl_count);
+	}
+
+	return len;
+}
+
+static int drm_clients_info(char *buf, char **start, off_t offset, int len,
+			    int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_clients_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+#if DRM_DEBUG_CODE
+
+static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_device_t	      *dev = (drm_device_t *)data;
+	drm_vma_entry_t	      *pt;
+	pgd_t		      *pgd;
+	pmd_t		      *pmd;
+	pte_t		      *pte;
+	unsigned long	      i;
+	struct vm_area_struct *vma;
+	unsigned long	      address;
+#if defined(__i386__)
+	unsigned int	      pgprot;
+#endif
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
+		       atomic_read(&dev->vma_count),
+		       high_memory, virt_to_phys(high_memory));
+	for (pt = dev->vmalist; pt; pt = pt->next) {
+		if (!(vma = pt->vma)) continue;
+		DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+			       pt->pid,
+			       vma->vm_start,
+			       vma->vm_end,
+			       vma->vm_flags & VM_READ	   ? 'r' : '-',
+			       vma->vm_flags & VM_WRITE	   ? 'w' : '-',
+			       vma->vm_flags & VM_EXEC	   ? 'x' : '-',
+			       vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+			       vma->vm_flags & VM_LOCKED   ? 'l' : '-',
+			       vma->vm_flags & VM_IO	   ? 'i' : '-',
+			       vma->vm_offset );
+#if defined(__i386__)
+		pgprot = pgprot_val(vma->vm_page_prot);
+		DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
+			       pgprot & _PAGE_PRESENT  ? 'p' : '-',
+			       pgprot & _PAGE_RW       ? 'w' : 'r',
+			       pgprot & _PAGE_USER     ? 'u' : 's',
+			       pgprot & _PAGE_PWT      ? 't' : 'b',
+			       pgprot & _PAGE_PCD      ? 'u' : 'c',
+			       pgprot & _PAGE_ACCESSED ? 'a' : '-',
+			       pgprot & _PAGE_DIRTY    ? 'd' : '-',
+			       pgprot & _PAGE_4M       ? 'm' : 'k',
+			       pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
+#endif		
+		DRM_PROC_PRINT("\n");
+		for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
+			pgd = pgd_offset(vma->vm_mm, i);
+			pmd = pmd_offset(pgd, i);
+			pte = pte_offset(pmd, i);
+			if (pte_present(*pte)) {
+				address = __pa(pte_page(*pte))
+					+ (i & (PAGE_SIZE-1));
+				DRM_PROC_PRINT("      0x%08lx -> 0x%08lx"
+					       " %c%c%c%c%c\n",
+					       i,
+					       address,
+					       pte_read(*pte)  ? 'r' : '-',
+					       pte_write(*pte) ? 'w' : '-',
+					       pte_exec(*pte)  ? 'x' : '-',
+					       pte_dirty(*pte) ? 'd' : '-',
+					       pte_young(*pte) ? 'a' : '-' );
+			} else {
+				DRM_PROC_PRINT("      0x%08lx\n", i);
+			}
+		}
+	}
+	
+	return len;
+}
+
+static int drm_vma_info(char *buf, char **start, off_t offset, int len,
+			int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_vma_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+#endif
+
+
+#if DRM_DMA_HISTOGRAM
+static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
+			   int *eof, void *data)
+{
+	drm_device_t	 *dev = (drm_device_t *)data;
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+	unsigned long	 slot_value = DRM_DMA_HISTOGRAM_INITIAL;
+	unsigned long	 prev_value = 0;
+	drm_buf_t	 *buffer;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+
+	DRM_PROC_PRINT("general statistics:\n");
+	DRM_PROC_PRINT("total	 %10u\n", atomic_read(&dev->histo.total));
+	DRM_PROC_PRINT("open	 %10u\n", atomic_read(&dev->total_open));
+	DRM_PROC_PRINT("close	 %10u\n", atomic_read(&dev->total_close));
+	DRM_PROC_PRINT("ioctl	 %10u\n", atomic_read(&dev->total_ioctl));
+	DRM_PROC_PRINT("irq	 %10u\n", atomic_read(&dev->total_irq));
+	DRM_PROC_PRINT("ctx	 %10u\n", atomic_read(&dev->total_ctx));
+	
+	DRM_PROC_PRINT("\nlock statistics:\n");
+	DRM_PROC_PRINT("locks	 %10u\n", atomic_read(&dev->total_locks));
+	DRM_PROC_PRINT("unlocks	 %10u\n", atomic_read(&dev->total_unlocks));
+	DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
+	DRM_PROC_PRINT("sleeps	 %10u\n", atomic_read(&dev->total_sleeps));
+
+
+	if (dma) {
+		DRM_PROC_PRINT("\ndma statistics:\n");
+		DRM_PROC_PRINT("prio	 %10u\n",
+			       atomic_read(&dma->total_prio));
+		DRM_PROC_PRINT("bytes	 %10u\n",
+			       atomic_read(&dma->total_bytes));
+		DRM_PROC_PRINT("dmas	 %10u\n",
+			       atomic_read(&dma->total_dmas));
+		DRM_PROC_PRINT("missed:\n");
+		DRM_PROC_PRINT("  dma	 %10u\n",
+			       atomic_read(&dma->total_missed_dma));
+		DRM_PROC_PRINT("  lock	 %10u\n",
+			       atomic_read(&dma->total_missed_lock));
+		DRM_PROC_PRINT("  free	 %10u\n",
+			       atomic_read(&dma->total_missed_free));
+		DRM_PROC_PRINT("  sched	 %10u\n",
+			       atomic_read(&dma->total_missed_sched));
+		DRM_PROC_PRINT("tried	 %10u\n",
+			       atomic_read(&dma->total_tried));
+		DRM_PROC_PRINT("hit	 %10u\n",
+			       atomic_read(&dma->total_hit));
+		DRM_PROC_PRINT("lost	 %10u\n",
+			       atomic_read(&dma->total_lost));
+		
+		buffer = dma->next_buffer;
+		if (buffer) {
+			DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
+		} else {
+			DRM_PROC_PRINT("next_buffer    none\n");
+		}
+		buffer = dma->this_buffer;
+		if (buffer) {
+			DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
+		} else {
+			DRM_PROC_PRINT("this_buffer    none\n");
+		}
+	}
+	
+
+	DRM_PROC_PRINT("\nvalues:\n");
+	if (dev->lock.hw_lock) {
+		DRM_PROC_PRINT("lock	       0x%08x\n",
+			       dev->lock.hw_lock->lock);
+	} else {
+		DRM_PROC_PRINT("lock		     none\n");
+	}
+	DRM_PROC_PRINT("context_flag   0x%08x\n", dev->context_flag);
+	DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag);
+	DRM_PROC_PRINT("dma_flag       0x%08x\n", dev->dma_flag);
+
+	DRM_PROC_PRINT("queue_count    %10d\n",	 dev->queue_count);
+	DRM_PROC_PRINT("last_context   %10d\n",	 dev->last_context);
+	DRM_PROC_PRINT("last_switch    %10lu\n", dev->last_switch);
+	DRM_PROC_PRINT("last_checked   %10d\n",	 dev->last_checked);
+		
+	
+	DRM_PROC_PRINT("\n		       q2d	  d2c	     c2f"
+		       "	q2c	   q2f	      dma	 sch"
+		       "	ctx	  lacq	     lhld\n\n");
+	for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
+		DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
+			       " %10u %10u %10u %10u %10u\n",
+			       i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
+			       i == DRM_DMA_HISTOGRAM_SLOTS - 1
+			       ? prev_value : slot_value ,
+			       
+			       atomic_read(&dev->histo
+					   .queued_to_dispatched[i]),
+			       atomic_read(&dev->histo
+					   .dispatched_to_completed[i]),
+			       atomic_read(&dev->histo
+					   .completed_to_freed[i]),
+			       
+			       atomic_read(&dev->histo
+					   .queued_to_completed[i]),
+			       atomic_read(&dev->histo
+					   .queued_to_freed[i]),
+			       atomic_read(&dev->histo.dma[i]),
+			       atomic_read(&dev->histo.schedule[i]),
+			       atomic_read(&dev->histo.ctx[i]),
+			       atomic_read(&dev->histo.lacq[i]),
+			       atomic_read(&dev->histo.lhld[i]));
+		prev_value = slot_value;
+		slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
+	}
+	return len;
+}
+
+static int drm_histo_info(char *buf, char **start, off_t offset, int len,
+			  int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_histo_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+#endif
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/sigio.c linux/drivers/char/drm/sigio.c
--- v2.3.17/linux/drivers/char/drm/sigio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/sigio.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,82 @@
+/* sigio.c -- Support for SIGIO handler -*- linux-c -*-
+ * Created: Thu Jun  3 15:39:18 1999 by faith@precisioninsight.com
+ * Revised: Thu Jun  3 16:16:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 21:11:29 faith Exp $
+ * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/sigio.c,v 1.2 1999/06/14 12:02:11 dawes Exp $
+ * 
+ */
+
+
+#ifdef XFree86Server
+# include "X.h"
+# include "xf86.h"
+# include "xf86drm.h"
+# include "xf86_OSlib.h"
+# include "xf86drm.h"
+#else
+# include <unistd.h>
+# include <signal.h>
+# include <fcntl.h>
+#endif
+
+/*
+ * Linux libc5 defines FASYNC, but not O_ASYNC.  Don't know if it is
+ * functional or not.
+ */
+#if defined(FASYNC) && !defined(O_ASYNC)
+#  define O_ASYNC FASYNC
+#endif
+
+int
+xf86InstallSIGIOHandler(int fd, void (*f)(int))
+{
+    struct sigaction sa;
+    struct sigaction osa;
+
+    sigemptyset(&sa.sa_mask);
+    sigaddset(&sa.sa_mask, SIGIO);
+    sa.sa_flags   = 0;
+    sa.sa_handler = f;
+    sigaction(SIGIO, &sa, &osa);
+    fcntl(fd, F_SETOWN, getpid());
+    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC);
+    return 0;
+}
+
+int
+xf86RemoveSIGIOHandler(int fd)
+{
+    struct sigaction sa;
+    struct sigaction osa;
+
+    sigemptyset(&sa.sa_mask);
+    sigaddset(&sa.sa_mask, SIGIO);
+    sa.sa_flags   = 0;
+    sa.sa_handler = SIG_DFL;
+    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC);
+    sigaction(SIGIO, &sa, &osa);
+    return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/drm/vm.c linux/drivers/char/drm/vm.c
--- v2.3.17/linux/drivers/char/drm/vm.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/drm/vm.c	Tue Sep  7 14:51:28 1999
@@ -0,0 +1,264 @@
+/* vm.c -- Memory mapping for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ * Revised: Fri Aug 20 22:48:11 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/vm.c,v 1.7 1999/08/21 02:48:34 faith Exp $
+ * $XFree86$
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+struct vm_operations_struct   drm_vm_ops = {
+	nopage:	 drm_vm_nopage,
+	open:	 drm_vm_open,
+	close:	 drm_vm_close,
+};
+
+struct vm_operations_struct   drm_vm_shm_ops = {
+	nopage:	 drm_vm_shm_nopage,
+	open:	 drm_vm_open,
+	close:	 drm_vm_close,
+};
+
+struct vm_operations_struct   drm_vm_dma_ops = {
+	nopage:	 drm_vm_dma_nopage,
+	open:	 drm_vm_open,
+	close:	 drm_vm_close,
+};
+
+unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+			    unsigned long address,
+			    int write_access)
+{
+	DRM_DEBUG("0x%08lx, %d\n", address, write_access);
+
+	return 0;		/* Disallow mremap */
+}
+
+unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+				unsigned long address,
+				int write_access)
+{
+	drm_file_t	 *priv	 = vma->vm_file->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	unsigned long	 physical;
+	unsigned long	 offset;
+	unsigned long	 page;
+
+	if (address > vma->vm_end) return 0; /* Disallow mremap */
+	if (!dev->lock.hw_lock)    return 0; /* Nothing allocated */
+
+	offset	 = address - vma->vm_start;
+	page	 = offset >> PAGE_SHIFT;
+	physical = (unsigned long)dev->lock.hw_lock + (offset & (~PAGE_MASK));
+	atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
+
+	DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+	return physical;
+}
+
+unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+				unsigned long address,
+				int write_access)
+{
+	drm_file_t	 *priv	 = vma->vm_file->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	unsigned long	 physical;
+	unsigned long	 offset;
+	unsigned long	 page;
+
+	if (!dma)		   return 0; /* Error */
+	if (address > vma->vm_end) return 0; /* Disallow mremap */
+	if (!dma->pagelist)	   return 0; /* Nothing allocated */
+
+	offset	 = address - vma->vm_start; /* vm_offset should be 0 */
+	page	 = offset >> PAGE_SHIFT;
+	physical = dma->pagelist[page] + (offset & (~PAGE_MASK));
+	atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
+
+	DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+	return physical;
+}
+
+void drm_vm_open(struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= vma->vm_file->private_data;
+	drm_device_t	*dev	= priv->dev;
+#if DRM_DEBUG_CODE
+	drm_vma_entry_t *vma_entry;
+#endif
+
+	DRM_DEBUG("0x%08lx,0x%08lx\n",
+		  vma->vm_start, vma->vm_end - vma->vm_start);
+	atomic_inc(&dev->vma_count);
+	MOD_INC_USE_COUNT;
+
+#if DRM_DEBUG_CODE
+	vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
+	if (vma_entry) {
+		down(&dev->struct_sem);
+		vma_entry->vma	= vma;
+		vma_entry->next = dev->vmalist;
+		vma_entry->pid	= current->pid;
+		dev->vmalist	= vma_entry;
+		up(&dev->struct_sem);
+	}
+#endif
+}
+
+void drm_vm_close(struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= vma->vm_file->private_data;
+	drm_device_t	*dev	= priv->dev;
+#if DRM_DEBUG_CODE
+	drm_vma_entry_t *pt, *prev;
+#endif
+
+	DRM_DEBUG("0x%08lx,0x%08lx\n",
+		  vma->vm_start, vma->vm_end - vma->vm_start);
+	MOD_DEC_USE_COUNT;
+	atomic_dec(&dev->vma_count);
+
+#if DRM_DEBUG_CODE
+	down(&dev->struct_sem);
+	for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
+		if (pt->vma == vma) {
+			if (prev) {
+				prev->next = pt->next;
+			} else {
+				dev->vmalist = pt->next;
+			}
+			drm_free(pt, sizeof(*pt), DRM_MEM_VMAS);
+			break;
+		}
+	}
+	up(&dev->struct_sem);
+#endif
+}
+
+int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	unsigned long	 length	 = vma->vm_end - vma->vm_start;
+	
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, vma->vm_offset);
+
+				/* Length must match exact page count */
+	if ((length >> PAGE_SHIFT) != dma->page_count) return -EINVAL;
+
+	vma->vm_ops   = &drm_vm_dma_ops;
+	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+	
+#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
+				/* In Linux 2.2.3 and above, this is
+				   handled in do_mmap() in mm/mmap.c. */
+	++filp->f_count;
+#endif
+	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
+	drm_vm_open(vma);
+	return 0;
+}
+
+int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_map_t	*map	= NULL;
+	int		i;
+	
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, vma->vm_offset);
+
+	if (!vma->vm_offset) return drm_mmap_dma(filp, vma);
+
+				/* A sequential search of a linked list is
+				   fine here because: 1) there will only be
+				   about 5-10 entries in the list and, 2) a
+				   DRI client only has to do this mapping
+				   once, so it doesn't have to be optimized
+				   for performance, even if the list was a
+				   bit longer. */
+	for (i = 0; i < dev->map_count; i++) {
+		map = dev->maplist[i];
+		if (map->offset == vma->vm_offset) break;
+	}
+	
+	if (i >= dev->map_count) return -EINVAL;
+	if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
+		return -EPERM;
+
+				/* Check for valid size. */
+	if (map->size != vma->vm_end - vma->vm_start) return -EINVAL;
+	
+
+	switch (map->type) {
+	case _DRM_FRAME_BUFFER:
+	case _DRM_REGISTERS:
+		if (vma->vm_offset >= __pa(high_memory)) {
+#if defined(__i386__)
+			if (boot_cpu_data.x86 > 3) {
+				pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+				pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+			}
+#endif
+			vma->vm_flags |= VM_IO;	/* not in core dump */
+		}
+		if (remap_page_range(vma->vm_start,
+				     vma->vm_offset,
+				     vma->vm_end - vma->vm_start,
+				     vma->vm_page_prot))
+				return -EAGAIN;
+		vma->vm_ops = &drm_vm_ops;
+		break;
+	case _DRM_SHM:
+		vma->vm_ops = &drm_vm_shm_ops;
+				/* Don't let this area swap.  Change when
+				   DRM_KERNEL advisory is supported. */
+		vma->vm_flags |= VM_LOCKED;
+		break;
+	default:
+		return -EINVAL;	/* This should never happen. */
+	}
+	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+	if (map->flags & _DRM_READ_ONLY) {
+		pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+	}
+
+	
+#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
+				/* In Linux 2.2.3 and above, this is
+				   handled in do_mmap() in mm/mmap.c. */
+	++filp->f_count;
+#endif
+	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
+	drm_vm_open(vma);
+	return 0;
+}
diff -u --recursive --new-file v2.3.17/linux/drivers/char/i2c-parport.c linux/drivers/char/i2c-parport.c
--- v2.3.17/linux/drivers/char/i2c-parport.c	Thu Jul  1 14:22:56 1999
+++ linux/drivers/char/i2c-parport.c	Wed Sep  8 11:51:22 1999
@@ -22,7 +22,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #define I2C_DELAY   10
 
diff -u --recursive --new-file v2.3.17/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c
--- v2.3.17/linux/drivers/char/joystick/joystick.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/joystick/joystick.c	Wed Sep  8 11:59:00 1999
@@ -43,7 +43,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/poll.h>
 #endif
 
diff -u --recursive --new-file v2.3.17/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.3.17/linux/drivers/char/mem.c	Thu Aug 12 10:41:30 1999
+++ linux/drivers/char/mem.c	Wed Sep  8 10:59:07 1999
@@ -268,6 +268,7 @@
 	return do_write_mem(file, (void*)p, p, buf, count, ppos);
 }
 
+#if !defined(CONFIG_PPC) && !defined(__mc68000__)
 static ssize_t read_port(struct file * file, char * buf,
 			 size_t count, loff_t *ppos)
 {
@@ -305,6 +306,7 @@
 	*ppos = i;
 	return tmp-buf;
 }
+#endif
 
 static ssize_t read_null(struct file * file, char * buf,
 			 size_t count, loff_t *ppos)
@@ -515,6 +517,7 @@
 	NULL		/* fsync */
 };
 
+#if !defined(CONFIG_PPC) && !defined(__mc68000__)
 static struct file_operations port_fops = {
 	memory_lseek,
 	read_port,
@@ -528,6 +531,7 @@
 	NULL,		/* no special release code */
 	NULL		/* fsync */
 };
+#endif
 
 static struct file_operations zero_fops = {
 	zero_lseek,
diff -u --recursive --new-file v2.3.17/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.3.17/linux/drivers/char/pc_keyb.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/pc_keyb.c	Wed Sep  8 11:51:22 1999
@@ -17,7 +17,7 @@
 
 #include <linux/config.h>
 
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/char/q40_keyb.c linux/drivers/char/q40_keyb.c
--- v2.3.17/linux/drivers/char/q40_keyb.c	Sun Aug 15 11:48:32 1999
+++ linux/drivers/char/q40_keyb.c	Wed Sep  8 11:51:22 1999
@@ -5,7 +5,7 @@
 
 #include <linux/config.h>
 
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.3.17/linux/drivers/i2o/i2o_config.c	Thu Aug  5 15:04:52 1999
+++ linux/drivers/i2o/i2o_config.c	Wed Sep  8 11:51:22 1999
@@ -25,10 +25,10 @@
 #include <linux/malloc.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 
 #include "i2o_proc.h"
 
diff -u --recursive --new-file v2.3.17/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.17/linux/drivers/i2o/i2o_core.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/i2o/i2o_core.c	Wed Sep  8 11:51:22 1999
@@ -31,9 +31,9 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
-#include <asm/spinlock.h>
 
 #include "i2o_lan.h"
 
diff -u --recursive --new-file v2.3.17/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.3.17/linux/drivers/i2o/i2o_lan.c	Wed Aug 18 11:38:59 1999
+++ linux/drivers/i2o/i2o_lan.c	Wed Sep  8 11:51:22 1999
@@ -38,7 +38,7 @@
 #include <linux/malloc.h>
 #include <linux/trdevice.h>
 #include <linux/init.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.3.17/linux/drivers/i2o/i2o_proc.c	Fri Aug  6 11:16:54 1999
+++ linux/drivers/i2o/i2o_proc.c	Wed Sep  8 11:51:22 1999
@@ -45,11 +45,11 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
-#include <asm/spinlock.h>
 
 
 #include "i2o_proc.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.3.17/linux/drivers/macintosh/macserial.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/macintosh/macserial.c	Wed Sep  8 10:59:07 1999
@@ -117,7 +117,7 @@
 static void probe_sccs(void);
 static void change_speed(struct mac_serial *info, struct termios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static void set_scc_power(struct mac_serial * info, int state);
+static int set_scc_power(struct mac_serial * info, int state);
 static int setup_scc(struct mac_serial * info);
 
 static struct tty_struct *serial_table[NUM_CHANNELS];
@@ -329,8 +329,8 @@
 			
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 			static int flip_buf_ovf;
-			++flip_buf_ovf;
-			printk("FB. overflow: %d\n", flip_buf_ovf);
+			if (++flip_buf_ovf <= 1)
+				printk("FB. overflow: %d\n", flip_buf_ovf);
 			break;
 		}
 		tty->flip.count++;
@@ -586,8 +586,10 @@
 {
 }
 
-static int startup(struct mac_serial * info)
+static int startup(struct mac_serial * info, int can_sleep)
 {
+	int delay;
+
 #ifdef SERIAL_DEBUG_OPEN
 	printk("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
 #endif
@@ -609,7 +611,7 @@
 	printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
 #endif
 
-	set_scc_power(info, 1);
+	delay = set_scc_power(info, 1);
 	
 	setup_scc(info);
 
@@ -620,6 +622,15 @@
 	info->flags |= ZILOG_INITIALIZED;
 	enable_irq(info->irq);
 
+	if (delay) {
+		if (can_sleep) {
+			/* we need to wait a bit before using the port */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(delay * HZ / 1000);
+		} else
+			mdelay(delay);
+	}
+
 	return 0;
 }
 
@@ -740,10 +751,18 @@
 	info->flags &= ~ZILOG_INITIALIZED;
 }
 
-static void set_scc_power(struct mac_serial * info, int state)
+/*
+ * Turn power on or off to the SCC and associated stuff
+ * (port drivers, modem, IR port, etc.)
+ * Returns the number of milliseconds we should wait before
+ * trying to use the port.
+ */
+static int set_scc_power(struct mac_serial * info, int state)
 {
+	int delay = 0;
+
 	if (feature_test(info->dev_node, FEATURE_Serial_enable) < 0)
-		return;		/* don't have serial power control */
+		return 0;	/* don't have serial power control */
 
 	/* The timings looks strange but that's the ones MacOS seems
 	   to use for the internal modem. I think we can use a lot faster
@@ -762,16 +781,13 @@
 			feature_set(info->dev_node, FEATURE_Serial_IO_A);
 		else
 			feature_set(info->dev_node, FEATURE_Serial_IO_B);
-		mdelay(1);
+		delay = 1;
 		
 		if (info->is_cobalt_modem){
 			feature_set(info->dev_node, FEATURE_Modem_Reset);
-	   		mdelay(15);
+	   		mdelay(5);
 			feature_clear(info->dev_node, FEATURE_Modem_Reset);
-			/* XXX Note the big 250ms, we should probably replace this 
-			   by something better since we have irqs disabled here
-			 */
-			mdelay(250);
+			delay = 1000;	/* wait for 1s before using */
 		}
 #ifdef CONFIG_PMAC_PBOOK
 		if (info->is_pwbk_ir)
@@ -786,7 +802,7 @@
 #ifdef SERIAL_DEBUG_POWER
 			printk(KERN_INFO "        (canceled by KGDB)\n");
 #endif
-			return;
+			return 0;
 		}
 #endif
 #ifdef CONFIG_XMON
@@ -794,7 +810,7 @@
 #ifdef SERIAL_DEBUG_POWER
 			printk(KERN_INFO "        (canceled by XMON)\n");
 #endif
-			return;
+			return 0;
 		}
 #endif
 		if (info->is_cobalt_modem) {
@@ -835,6 +851,7 @@
 			mdelay(5);
 		}
 	}
+	return delay;
 }
 
 
@@ -1796,7 +1813,7 @@
 	 * Start up serial port
 	 */
 
-	retval = startup(info);
+	retval = startup(info, 1);
 	if (retval)
 		return retval;
 
diff -u --recursive --new-file v2.3.17/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c
--- v2.3.17/linux/drivers/macintosh/mediabay.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/macintosh/mediabay.c	Wed Sep  8 10:59:07 1999
@@ -98,9 +98,7 @@
  * Therefore we do it all by polling the media bay once each tick.
  */
 
-__pmac /* I don't know of any chrp with a mediabay -- Cort */
-
-void
+void __pmac
 media_bay_init(void)
 {
 	struct device_node *np;
@@ -174,7 +172,7 @@
 }
 #endif
 
-int
+int __pmac
 check_media_bay(struct device_node *which_bay, int what)
 {
 #ifdef CONFIG_BLK_DEV_IDE
@@ -192,7 +190,7 @@
 	return -ENODEV;
 }
 
-int
+int __pmac
 check_media_bay_by_base(unsigned long base, int what)
 {
 #ifdef CONFIG_BLK_DEV_IDE
@@ -211,7 +209,7 @@
 	return -ENODEV;
 }
 
-int
+int __pmac
 media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
 	int irq, int index)
 {
@@ -238,7 +236,7 @@
  * with the IDE driver.  It needs to be a thread because
  * ide_register can't be called from interrupt context.
  */
-int
+int __pmac
 media_bay_task(void *x)
 {
 	volatile struct media_bay_info* bay;
@@ -294,7 +292,7 @@
 	}
 }
 
-void
+void __pmac
 poll_media_bay(int which)
 {
 	int id = MB_CONTENTS(which);
@@ -309,7 +307,7 @@
 	}
 }
 
-static void
+static void __pmac
 set_media_bay(int which, int id)
 {
 	volatile struct media_bay_info* bay;
diff -u --recursive --new-file v2.3.17/linux/drivers/net/3c501.c linux/drivers/net/3c501.c
--- v2.3.17/linux/drivers/net/3c501.c	Wed Aug 18 11:36:41 1999
+++ linux/drivers/net/3c501.c	Wed Sep  8 11:51:21 1999
@@ -95,10 +95,10 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/config.h>	/* for CONFIG_IP_MULTICAST */
+#include <linux/spinlock.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.3.17/linux/drivers/net/3c507.c	Wed Aug 18 11:36:41 1999
+++ linux/drivers/net/3c507.c	Wed Sep  8 11:51:21 1999
@@ -50,11 +50,11 @@
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/spinlock.h>
 #include <linux/errno.h>
 
 #include <linux/netdevice.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.3.17/linux/drivers/net/3c509.c	Wed Aug 18 11:36:41 1999
+++ linux/drivers/net/3c509.c	Wed Sep  8 11:51:21 1999
@@ -64,8 +64,8 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>	/* for udelay() */
+#include <linux/spinlock.h>
 
-#include <asm/spinlock.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- v2.3.17/linux/drivers/net/3c59x.c	Wed Aug 18 11:36:41 1999
+++ linux/drivers/net/3c59x.c	Wed Sep  8 11:14:32 1999
@@ -263,13 +263,24 @@
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
 	{"3c905B Cyclone 100baseTx",	0x10B7, 0x9055, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
+	{"3c905B Cyclone 10/100/BNC",	0x10B7, 0x9058, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
 	{"3c905B-FX Cyclone 100baseFx",	0x10B7, 0x905A, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c905C Tornado",	0x10B7, 0x9200, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
 	{"3c980 Cyclone",	0x10B7, 0x9800, 0xfff0,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3cSOHO100-TX Hurricane",	0x10B7, 0x7646, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c555 Laptop Hurricane",	0x10B7, 0x5055, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
 	{"3c575 Boomerang CardBus",		0x10B7, 0x5057, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
 	{"3CCFE575 Cyclone CardBus",	0x10B7, 0x5157, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
+	 128, vortex_probe1},
+	{"3CCFE656 Cyclone CardBus",	0x10B7, 0x6560, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
 	 128, vortex_probe1},
 	{"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
diff -u --recursive --new-file v2.3.17/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.3.17/linux/drivers/net/8390.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/8390.c	Wed Sep  8 11:14:32 1999
@@ -192,7 +192,7 @@
 
 static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int length, send_length, output_page;
 	unsigned long flags;
@@ -405,7 +405,7 @@
 void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
-	int e8390_base;
+	long e8390_base;
 	int interrupts, nr_serviced = 0;
 	struct ei_device *ei_local;
     
@@ -518,7 +518,7 @@
 
 static void ei_tx_err(struct net_device *dev)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	unsigned char txsr = inb_p(e8390_base+EN0_TSR);
 	unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
@@ -556,7 +556,7 @@
 
 static void ei_tx_intr(struct net_device *dev)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int status = inb(e8390_base + EN0_TSR);
     
@@ -646,7 +646,7 @@
 
 static void ei_receive(struct net_device *dev)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	unsigned char rxing_page, this_frame, next_frame;
 	unsigned short current_offset;
@@ -775,7 +775,7 @@
 
 static void ei_rx_overrun(struct net_device *dev)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
 	unsigned char was_txing, must_resend = 0;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
     
@@ -844,7 +844,7 @@
  
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
-	int ioaddr = dev->base_addr;
+	long ioaddr = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	unsigned long flags;
     
@@ -919,7 +919,7 @@
  
 static void do_set_multicast_list(struct net_device *dev)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
 	int i;
 	struct ei_device *ei_local = (struct ei_device*)dev->priv;
 
@@ -1024,7 +1024,7 @@
 
 void NS8390_init(struct net_device *dev, int startp)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int i;
 	int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
@@ -1088,7 +1088,7 @@
 static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
 								int start_page)
 {
-	int e8390_base = dev->base_addr;
+	long e8390_base = dev->base_addr;
  	struct ei_device *ei_local = (struct ei_device *) dev->priv;
    
 	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
diff -u --recursive --new-file v2.3.17/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.17/linux/drivers/net/Config.in	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/Config.in	Thu Sep  9 13:10:12 1999
@@ -150,6 +150,7 @@
       tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
       bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
     fi
+    tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
   fi
   bool 'Pocket and portable adaptors' CONFIG_NET_POCKET
   if [ "$CONFIG_NET_POCKET" = "y" ]; then
@@ -307,4 +308,8 @@
     dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB
     dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
 fi
+fi
+
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+   source drivers/net/pcmcia/Config.in
 fi
diff -u --recursive --new-file v2.3.17/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.17/linux/drivers/net/Makefile	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/Makefile	Fri Sep 10 11:07:34 1999
@@ -5,7 +5,7 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc
+ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc pcmcia
 
 L_TARGET := net.a
 L_OBJS   := auto_irq.o
@@ -29,6 +29,15 @@
 CONFIG_SYNCPPP_BUILTIN :=
 CONFIG_SYNCPPP_MODULE  :=
 
+ifeq ($(CONFIG_PCMCIA),y)
+  SUB_DIRS += pcmcia
+  MOD_SUB_DIRS += pcmcia
+else
+  ifeq ($(CONFIG_PCMCIA),m)
+    MOD_SUB_DIRS += pcmcia
+  endif
+endif
+
 ifeq ($(CONFIG_ISDN),y)
   ifeq ($(CONFIG_ISDN_PPP),y)
     CONFIG_SLHC_BUILTIN = y
@@ -1116,6 +1125,14 @@
 else
   ifeq ($(CONFIG_BMAC),m)
   M_OBJS += bmac.o
+  endif
+endif
+
+ifeq ($(CONFIG_ADAPTEC_STARFIRE),y)
+L_OBJS += starfire.o
+else
+  ifeq ($(CONFIG_ADAPTEC_STARFIRE),m)
+  M_OBJS += starfire.o
   endif
 endif
 
diff -u --recursive --new-file v2.3.17/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.17/linux/drivers/net/Space.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/Space.c	Wed Sep  8 11:14:32 1999
@@ -118,6 +118,7 @@
 extern int dec_lance_probe(struct net_device *);
 extern int mvme147lance_probe(struct net_device *dev);
 extern int via_rhine_probe(struct net_device *dev);
+extern int starfire_probe(struct net_device *dev);
 extern int tc515_probe(struct net_device *dev);
 extern int lance_probe(struct net_device *dev);
 extern int rcpci_probe(struct net_device *);
@@ -223,6 +224,9 @@
 #endif
 #ifdef CONFIG_VIA_RHINE
 	{via_rhine_probe, 0},
+#endif
+#ifdef CONFIG_ADAPTEC_STARFIRE
+	{starfire_probe, 0},
 #endif
 	{NULL, 0},
 };
diff -u --recursive --new-file v2.3.17/linux/drivers/net/cosa.c linux/drivers/net/cosa.c
--- v2.3.17/linux/drivers/net/cosa.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/cosa.c	Wed Sep  8 11:51:22 1999
@@ -90,6 +90,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
+#include <linux/spinlock.h>
 
 #undef COSA_SLOW_IO	/* for testing purposes only */
 #undef REALLY_SLOW_IO
@@ -97,7 +98,6 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
-#include <asm/spinlock.h>
 
 #include "syncppp.h"
 #include "cosa.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.3.17/linux/drivers/net/de4x5.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/de4x5.c	Wed Sep  8 11:51:22 1999
@@ -446,6 +446,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/version.h>
+#include <linux/spinlock.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -453,7 +454,6 @@
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.3.17/linux/drivers/net/eepro.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/eepro.c	Wed Sep  8 11:51:22 1999
@@ -150,7 +150,7 @@
 /* For linux 2.1.xx */
 #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- v2.3.17/linux/drivers/net/eepro100.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/eepro100.c	Wed Sep  8 11:51:22 1999
@@ -94,7 +94,7 @@
 #include <linux/bios32.h>		/* Ignore the bogus warning in 2.1.100+ */
 #endif
 #endif
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
 
@@ -583,10 +583,10 @@
 #endif
 		/* Remove I/O space marker in bit 0. */
 		if (pciaddr & 1) {
-			ioaddr = pciaddr & ~3;
+			ioaddr = pciaddr & ~3UL;
 			if (check_region(ioaddr, 32))
 				continue;
-		} else if ((ioaddr = (long)ioremap(pciaddr & ~0xf, 0x1000)) == 0) {
+		} else if ((ioaddr = (long)ioremap(pciaddr & ~0xfUL, 0x1000)) == 0) {
 			printk(KERN_INFO "Failed to map PCI address %#x.\n",
 				   pciaddr);
 			continue;
diff -u --recursive --new-file v2.3.17/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.3.17/linux/drivers/net/eexpress.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/eexpress.c	Wed Sep  8 11:51:22 1999
@@ -121,7 +121,7 @@
 #include <linux/skbuff.h>
 #include <linux/malloc.h>
 
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #ifndef NET_DEBUG
 #define NET_DEBUG 4
diff -u --recursive --new-file v2.3.17/linux/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c
--- v2.3.17/linux/drivers/net/fc/iph5526.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/fc/iph5526.c	Wed Sep  8 11:59:00 1999
@@ -47,9 +47,9 @@
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/timer.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 
 #include <linux/netdevice.h>
 #include <linux/fcdevice.h> /* had the declarations for init_fcdev among others + includes if_fcdevice.h */
diff -u --recursive --new-file v2.3.17/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.3.17/linux/drivers/net/ibmtr.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/ibmtr.c	Wed Sep  8 11:51:22 1999
@@ -149,10 +149,10 @@
 #include <linux/trdevice.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <net/checksum.h>
 
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- v2.3.17/linux/drivers/net/irda/irport.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/irda/irport.c	Wed Sep  8 11:59:00 1999
@@ -47,11 +47,11 @@
 #include <linux/serial_reg.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c
--- v2.3.17/linux/drivers/net/ne2k-pci.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/ne2k-pci.c	Wed Sep  8 11:14:32 1999
@@ -105,7 +105,7 @@
 #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
 
 int ne2k_pci_probe(struct net_device *dev);
-static struct net_device *ne2k_pci_probe1(struct net_device *dev, int ioaddr, int irq,
+static struct net_device *ne2k_pci_probe1(struct net_device *dev, long ioaddr, int irq,
 									  int chip_idx);
 
 static int ne2k_pci_open(struct net_device *dev);
@@ -196,9 +196,9 @@
 		return -ENODEV;
 
 	while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev)) != NULL) {
-		u8 pci_irq_line;
+		int pci_irq_line;
 		u16 pci_command, new_command;
-		u32 pci_ioaddr;
+		unsigned long pci_ioaddr;
 
 		/* Note: some vendor IDs (RealTek) have non-NE2k cards as well. */
 		for (i = 0; pci_clone_list[i].vendor != 0; i++)
@@ -232,19 +232,19 @@
 				   pci_command, new_command);
 			pci_write_config_word(pdev, PCI_COMMAND, new_command);
 		}
-
+#ifndef __sparc__
 		if (pci_irq_line <= 0 || pci_irq_line >= NR_IRQS)
 			printk(KERN_WARNING "  WARNING: The PCI BIOS assigned this PCI NE2k"
 				   " card to IRQ %d, which is unlikely to work!.\n"
 				   KERN_WARNING " You should use the PCI BIOS setup to assign"
 				   " a valid IRQ line.\n", pci_irq_line);
-
-		printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#x, IRQ %d.\n",
+#endif
+		printk("ne2k-pci.c: PCI NE2000 clone '%s' at I/O %#lx, IRQ %d.\n",
 			   pci_clone_list[i].name, pci_ioaddr, pci_irq_line);
 		dev = ne2k_pci_probe1(dev, pci_ioaddr, pci_irq_line, i);
 		if (dev == 0) {
 			/* Should not happen. */
-			printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#x failed.\n",
+			printk(KERN_ERR "ne2k-pci: Probe of PCI card at %#lx failed.\n",
 				   pci_ioaddr);
 			continue;
 		} else {
@@ -263,7 +263,7 @@
 	return cards_found ? 0 : -ENODEV;
 }
 
-static struct net_device __init *ne2k_pci_probe1(struct net_device *dev, int ioaddr, int irq, int chip_idx)
+static struct net_device __init *ne2k_pci_probe1(struct net_device *dev, long ioaddr, int irq, int chip_idx)
 {
 	int i;
 	unsigned char SA_prom[32];
@@ -340,7 +340,6 @@
 
 	/* Note: all PCI cards have at least 16 bit access, so we don't have
 	   to check for 8 bit cards.  Most cards permit 32 bit access. */
-
 	if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) {
 		for (i = 0; i < 4 ; i++)
 			((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
@@ -367,7 +366,7 @@
 
 	request_region(ioaddr, NE_IO_EXTENT, dev->name);
 
-	printk("%s: %s found at %#x, IRQ %d, ",
+	printk("%s: %s found at %#lx, IRQ %d, ",
 		   dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
 	for(i = 0; i < 6; i++) {
 		printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
@@ -447,7 +446,7 @@
 ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
 
-	int nic_base = dev->base_addr;
+	long nic_base = dev->base_addr;
 
 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
 	if (ei_status.dmaing) {
@@ -485,7 +484,7 @@
 static void
 ne2k_pci_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
 {
-	int nic_base = dev->base_addr;
+	long nic_base = dev->base_addr;
 	char *buf = skb->data;
 
 	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
@@ -530,7 +529,7 @@
 ne2k_pci_block_output(struct net_device *dev, int count,
 		const unsigned char *buf, const int start_page)
 {
-	int nic_base = NE_BASE;
+	long nic_base = NE_BASE;
 	unsigned long dma_start;
 
 	/* On little-endian it's always safe to round the count up for
diff -u --recursive --new-file v2.3.17/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.3.17/linux/drivers/net/pcmcia/3c589_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/3c589_cs.c	Fri Sep 10 10:33:04 1999
@@ -0,0 +1,1177 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for the 3com 3c589 card.
+    
+    Copyright (C) 1998 David A. Hinds -- dhinds@hyper.stanford.edu
+
+    3c589_cs.c 1.126 1999/06/14 17:35:34
+
+    The network driver code is based on Donald Becker's 3c589 code:
+    
+    Written 1994 by Donald Becker.
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.  This software may be used and
+    distributed according to the terms of the GNU Public License,
+    incorporated herein by reference.
+    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+/* To minimize the size of the driver source I only define operating
+   constants if they are used several times.  You'll need the manual
+   if you want to understand driver details. */
+/* Offsets from base I/O address. */
+#define EL3_DATA	0x00
+#define EL3_TIMER	0x0a
+#define EL3_CMD		0x0e
+#define EL3_STATUS	0x0e
+#define ID_PORT		0x100
+#define	EEPROM_READ	0x80
+
+#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
+
+/* The top five bits written to EL3_CMD are a command, the lower
+   11 bits are the parameter, if applicable. */
+enum c509cmd {
+    TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+    RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
+    TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+    FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+    SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+    SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
+    StatsDisable = 22<<11, StopCoax = 23<<11,
+};
+
+enum c509status {
+    IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+    TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+    IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000
+};
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+    RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+};
+
+/* Register window 1 offsets, the window used in normal operation. */
+#define TX_FIFO		0x00
+#define RX_FIFO		0x00
+#define RX_STATUS 	0x08
+#define TX_STATUS 	0x0B
+#define TX_FREE		0x0C	/* Remaining free bytes in Tx buffer. */
+
+#define WN0_IRQ		0x08	/* Window 0: Set IRQ line in bits 12-15. */
+#define WN4_MEDIA	0x0A	/* Window 4: Various transcvr/media bits. */
+#define MEDIA_TP	0x00C0	/* Enable link beat and jabber for 10baseT. */
+#define MEDIA_LED	0x0001	/* Enable link light on 3C589E cards. */
+
+/* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT	((400*HZ)/1000)
+
+struct el3_private {
+    dev_node_t node;
+    struct net_device_stats stats;
+    /* For transceiver monitoring */
+    struct timer_list media;
+    u_short	media_status;
+    u_short	fast_poll;
+    u_long	last_irq;
+};
+
+static char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"3c589_cs.c 1.126 1999/06/14 17:35:34 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Special hook for setting if_port when module is loaded */
+static int if_port = 0;
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(if_port, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+static void tc589_config(dev_link_t *link);
+static void tc589_release(u_long arg);
+static int tc589_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+static ushort read_eeprom(short ioaddr, int index);
+static void tc589_reset(struct net_device *dev);
+static void media_check(u_long arg);
+static int el3_config(struct net_device *dev, struct ifmap *map);
+static int el3_open(struct net_device *dev);
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void update_stats(int addr, struct net_device *dev);
+static struct net_device_stats *el3_get_stats(struct net_device *dev);
+static int el3_rx(struct net_device *dev);
+static int el3_close(struct net_device *dev);
+
+static void set_multicast_list(struct net_device *dev);
+
+static dev_info_t dev_info = "3c589_cs";
+
+static dev_link_t *tc589_attach(void);
+static void tc589_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    tc589_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    We never need to do anything when a tc589 device is "initialized"
+    by the net software, because we only register already-found cards.
+    
+======================================================================*/
+
+static int tc589_init(struct net_device *dev)
+{
+    return 0;
+}
+
+/*======================================================================
+
+    tc589_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *tc589_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    int i, ret;
+
+    DEBUG(0, "3c589_attach()\n");
+    flush_stale_links();
+    
+    /* Create new ethernet device */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &tc589_release;
+    link->release.data = (u_long)link;
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+    link->io.IOAddrLines = 4;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &el3_interrupt;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+    
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    memset(dev, 0, sizeof(struct net_device));
+    
+    /* Make up a EL3-specific-data structure. */
+    dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL);
+    memset(dev->priv, 0, sizeof(struct el3_private));
+    
+    /* The EL3-specific entries in the device structure. */
+    dev->hard_start_xmit = &el3_start_xmit;
+    dev->set_config = &el3_config;
+    dev->get_stats = &el3_get_stats;
+    dev->set_multicast_list = &set_multicast_list;
+    ether_setup(dev);
+    dev->name = ((struct el3_private *)dev->priv)->node.dev_name;
+    dev->init = &tc589_init;
+    dev->open = &el3_open;
+    dev->stop = &el3_close;
+    dev->tbusy = 1;
+    link->priv = link->irq.Instance = dev;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &tc589_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	tc589_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* tc589_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void tc589_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    long flags;
+    
+    DEBUG(0, "3c589_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    save_flags(flags);
+    cli();
+    if (link->state & DEV_RELEASE_PENDING) {
+	del_timer(&link->release);
+	link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+    
+    if (link->state & DEV_CONFIG) {
+	tc589_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+    
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->priv) {
+	struct net_device *dev = link->priv;
+	if (link->dev != NULL)
+	    unregister_netdev(dev);
+	if (dev->priv)
+	    kfree_s(dev->priv, sizeof(struct el3_private));
+	kfree_s(link->priv, sizeof(struct net_device));
+    }
+    kfree_s(link, sizeof(struct dev_link_t));
+    
+} /* tc589_detach */
+
+/*======================================================================
+
+    tc589_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+    
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void tc589_config(dev_link_t *link)
+{
+    client_handle_t handle;
+    struct net_device *dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_short buf[32];
+    int last_fn, last_ret, i, j, multi = 0;
+    short ioaddr, *phys_addr;
+    char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+    
+    handle = link->handle;
+    dev = link->priv;
+    phys_addr = (short *)dev->dev_addr;
+
+    DEBUG(0, "3c589_config(0x%p)\n", link);
+
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Is this a 3c562? */
+    tuple.DesiredTuple = CISTPL_MANFID;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
+	(CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) {
+	if (le16_to_cpu(buf[0]) != MANFID_3COM)
+	    printk(KERN_INFO "3c589_cs: hmmm, is this really a "
+		   "3Com card??\n");
+	multi = (le16_to_cpu(buf[1]) == PRODID_3COM_3C562);
+    }
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* For the 3c562, the base address must be xx00-xx7f */
+    for (i = j = 0; j < 0x400; j += 0x10) {
+	if (multi && (j & 0x80)) continue;
+	link->io.BasePort1 = j ^ 0x300;
+	i = CardServices(RequestIO, link->handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    }
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIO, i);
+	goto failed;
+    }
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+	
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    dev->tbusy = 0;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "3c589_cs: register_netdev() failed\n");
+	goto failed;
+    }
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    ioaddr = dev->base_addr;
+    EL3WINDOW(0);
+
+    /* The 3c589 has an extra EEPROM for configuration info, including
+       the hardware address.  The 3c562 puts the address in the CIS. */
+    tuple.DesiredTuple = 0x88;
+    if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) {
+	CardServices(GetTupleData, handle, &tuple);
+	for (i = 0; i < 3; i++)
+	    phys_addr[i] = htons(buf[i]);
+    } else {
+	for (i = 0; i < 3; i++)
+	    phys_addr[i] = htons(read_eeprom(ioaddr, i));
+	if (phys_addr[0] == 0x6060) {
+	    printk(KERN_NOTICE "3c589_cs: IO port conflict at 0x%03lx"
+		   "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+	    goto failed;
+	}
+    }
+    
+    link->dev = &((struct el3_private *)dev->priv)->node;
+    
+    /* The address and resource configuration register aren't loaded from
+       the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
+    outw(0x3f00, ioaddr + 8);
+
+    /* The if_port symbol can be set when the module is loaded */
+    if ((if_port >= 0) && (if_port <= 3))
+	dev->if_port = if_port;
+    else
+	printk(KERN_NOTICE "3c589_cs: invalid if_port requested\n");
+    
+    printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, %s xcvr, "
+	   "hw_addr ", dev->name, (multi ? "562" : "589"),
+	   dev->base_addr, dev->irq, if_names[dev->if_port]);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    i = inl(ioaddr);
+    printk(KERN_INFO "  %dK FIFO split %s Rx:Tx\n",
+	   (i & 7) ? 32 : 8, ram_split[(i >> 16) & 3]);
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    tc589_release((u_long)link);
+    return;
+    
+} /* tc589_config */
+
+/*======================================================================
+
+    After a card is removed, tc589_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void tc589_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "3c589_release(0x%p)\n", link);
+    
+    if (link->open) {
+	DEBUG(1, "3c589_cs: release postponed, '%s' still open\n",
+	      link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+    
+} /* tc589_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+    
+======================================================================*/
+
+static int tc589_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    struct net_device *dev = link->priv;
+    
+    DEBUG(1, "3c589_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    dev->tbusy = 1; dev->start = 0;
+	    link->release.expires = jiffies + (HZ/20);
+	    add_timer(&link->release);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	tc589_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open) {
+		dev->tbusy = 1; dev->start = 0;
+	    }
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		tc589_reset(dev);
+		dev->tbusy = 0; dev->start = 1;
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* tc589_event */
+
+/*====================================================================*/
+
+/*
+  Use this for commands that may take time to finish
+*/
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+    int i = 100;
+    outw(cmd, dev->base_addr + EL3_CMD);
+    while (--i > 0)
+	if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
+    if (i == 0)
+	printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
+	       dev->name, cmd);
+}
+
+/*
+  Read a word from the EEPROM using the regular EEPROM access register.
+  Assume that we are in register window zero.
+*/
+static ushort read_eeprom(short ioaddr, int index)
+{
+    int i;
+    outw(EEPROM_READ + index, ioaddr + 10);
+    /* Reading the eeprom takes 162 us */
+    for (i = 1620; i >= 0; i--)
+	if ((inw(ioaddr + 10) & 0x8000) == 0)
+	    break;
+    return inw(ioaddr + 12);
+}
+
+/*
+  Set transceiver type, perhaps to something other than what the user
+  specified in dev->if_port.
+*/
+static void tc589_set_xcvr(struct net_device *dev, int if_port)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ushort ioaddr = dev->base_addr;
+    
+    EL3WINDOW(0);
+    switch (if_port) {
+    case 0: case 1: outw(0, ioaddr + 6); break;
+    case 2: outw(3<<14, ioaddr + 6); break;
+    case 3: outw(1<<14, ioaddr + 6); break;
+    }
+    /* On PCMCIA, this just turns on the LED */
+    outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+    /* 10baseT interface, enable link beat and jabber check. */
+    EL3WINDOW(4);
+    outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
+    EL3WINDOW(1);
+    lp->media_status = (if_port < 2) ? 0x8800 : 0x4800;
+    lp->last_irq = jiffies;
+}
+
+static void dump_status(struct net_device *dev)
+{
+    int ioaddr = dev->base_addr;
+    EL3WINDOW(1);
+    printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
+	   "%02x  tx free %04x\n", inw(ioaddr+EL3_STATUS),
+	   inw(ioaddr+RX_STATUS), inb(ioaddr+TX_STATUS),
+	   inw(ioaddr+TX_FREE));
+    EL3WINDOW(4);
+    printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"
+	   " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
+	   inw(ioaddr+0x08), inw(ioaddr+0x0a));
+    EL3WINDOW(1);
+}
+
+/* Reset and restore all of the 3c589 registers. */
+static void tc589_reset(struct net_device *dev)
+{
+    ushort ioaddr = dev->base_addr;
+    int i;
+    
+    EL3WINDOW(0);
+    outw(0x0001, ioaddr + 4);			/* Activate board. */ 
+    outw(0x3f00, ioaddr + 8);			/* Set the IRQ line. */
+    
+    /* Set the station address in window 2. */
+    EL3WINDOW(2);
+    for (i = 0; i < 6; i++)
+	outb(dev->dev_addr[i], ioaddr + i);
+
+    tc589_set_xcvr(dev, dev->if_port);
+    
+    /* Switch to the stats window, and clear all stats by reading. */
+    outw(StatsDisable, ioaddr + EL3_CMD);
+    EL3WINDOW(6);
+    for (i = 0; i < 9; i++)
+	inb(ioaddr+i);
+    inw(ioaddr + 10);
+    inw(ioaddr + 12);
+    
+    /* Switch to register set 1 for normal use. */
+    EL3WINDOW(1);
+
+    /* Accept b-cast and phys addr only. */
+    outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+    outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+    outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+    outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+    /* Allow status bits to be seen. */
+    outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+    /* Ack all pending events, and set active indicator mask. */
+    outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+	 ioaddr + EL3_CMD);
+    outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+	 | AdapterFailure, ioaddr + EL3_CMD);
+}
+
+static int el3_config(struct net_device *dev, struct ifmap *map)
+{
+    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+	if (map->port <= 3) {
+	    dev->if_port = map->port;
+	    printk(KERN_INFO "%s: switched to %s port\n",
+		   dev->name, if_names[dev->if_port]);
+	    tc589_set_xcvr(dev, dev->if_port);
+	} else
+	    return -EINVAL;
+    }
+    return 0;
+}
+
+static int el3_open(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    dev_link_t *link;
+    
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+    dev->interrupt = 0; dev->tbusy = 0; dev->start = 1;
+    
+    tc589_reset(dev);
+    lp->media.function = &media_check;
+    lp->media.data = (u_long)dev;
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+
+    DEBUG(1, "%s: opened, status %4.4x.\n",
+	  dev->name, inw(dev->base_addr + EL3_STATUS));
+    
+    return 0;					/* Always succeed */
+}
+
+static void el3_tx_timeout(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    int ioaddr = dev->base_addr;
+    
+    printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
+    dump_status(dev);
+    lp->stats.tx_errors++;
+    dev->trans_start = jiffies;
+    /* Issue TX_RESET and TX_START commands. */
+    wait_for_completion(dev, TxReset);
+    outw(TxEnable, ioaddr + EL3_CMD);
+    dev->tbusy = 0;
+}
+
+static void pop_tx_status(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    int ioaddr = dev->base_addr;
+    int i;
+    
+    /* Clear the Tx status stack. */
+    for (i = 32; i > 0; i--) {
+	u_char tx_status = inb(ioaddr + TX_STATUS);
+	if (!(tx_status & 0x84)) break;
+	/* reset transmitter on jabber error or underrun */
+	if (tx_status & 0x30)
+	    wait_for_completion(dev, TxReset);
+	if (tx_status & 0x38) {
+	    DEBUG(1, "%s: transmit error: status 0x%02x\n",
+		  dev->name, tx_status);
+	    outw(TxEnable, ioaddr + EL3_CMD);
+	    lp->stats.tx_aborted_errors++;
+	}
+	outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
+    }
+}
+
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    int ioaddr = dev->base_addr;
+
+    /* Transmitter timeout, serious problems. */
+    if (dev->tbusy) {
+	if (jiffies - dev->trans_start < TX_TIMEOUT)
+	    return 1;
+	el3_tx_timeout(dev);
+    }
+
+    DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
+	  "status %4.4x.\n", dev->name, (long)skb->len,
+	  inw(ioaddr + EL3_STATUS));
+
+    /* Avoid timer-based retransmission conflicts. */
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+	printk(KERN_NOTICE "%s: transmitter access conflict.\n",
+	       dev->name);
+    else {
+	lp->stats.tx_bytes += skb->len;
+	/* Put out the doubleword header... */
+	outw(skb->len, ioaddr + TX_FIFO);
+	outw(0x00, ioaddr + TX_FIFO);
+	/* ... and the packet rounded to a doubleword. */
+	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+	
+	dev->trans_start = jiffies;
+	if (inw(ioaddr + TX_FREE) > 1536) {
+	    dev->tbusy = 0;
+	} else
+	    /* Interrupt us when the FIFO has room for max-sized packet. */
+	    outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+    }
+
+    dev_kfree_skb(skb);
+    pop_tx_status(dev);
+    
+    return 0;
+}
+
+/* The EL3 interrupt handler. */
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct net_device *dev = (struct net_device *)dev_id;
+    struct el3_private *lp;
+    int ioaddr, status;
+    int i = 0;
+    
+    if ((dev == NULL) || !dev->start)
+	return;
+    lp = (struct el3_private *)dev->priv;
+    ioaddr = dev->base_addr;
+
+#ifdef PCMCIA_DEBUG
+    if (dev->interrupt) {
+	printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
+	       dev->name);
+	return;
+    }
+    dev->interrupt = 1;
+    DEBUG(3, "%s: interrupt, status %4.4x.\n",
+	  dev->name, inw(ioaddr + EL3_STATUS));
+#endif
+    
+    while ((status = inw(ioaddr + EL3_STATUS)) &
+	(IntLatch | RxComplete | StatsFull)) {
+	if ((dev->start == 0) || ((status & 0xe000) != 0x2000)) {
+	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);
+	    break;
+	}
+	
+	if (status & RxComplete)
+	    el3_rx(dev);
+	
+	if (status & TxAvailable) {
+	    DEBUG(3, "    TX room bit was handled.\n");
+	    /* There's room in the FIFO for a full-sized packet. */
+	    outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+	    dev->tbusy = 0;
+	    mark_bh(NET_BH);
+	}
+	
+	if (status & TxComplete)
+	    pop_tx_status(dev);
+
+	if (status & (AdapterFailure | RxEarly | StatsFull)) {
+	    /* Handle all uncommon interrupts. */
+	    if (status & StatsFull)		/* Empty statistics. */
+		update_stats(ioaddr, dev);
+	    if (status & RxEarly) {		/* Rx early is unused. */
+		el3_rx(dev);
+		outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+	    }
+	    if (status & AdapterFailure) {
+		u16 fifo_diag;
+		EL3WINDOW(4);
+		fifo_diag = inw(ioaddr + 4);
+		EL3WINDOW(1);
+		printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
+		       " register %04x.\n", dev->name, fifo_diag);
+		if (fifo_diag & 0x0400) {
+		    /* Tx overrun */
+		    wait_for_completion(dev, TxReset);
+		    outw(TxEnable, ioaddr + EL3_CMD);
+		}
+		if (fifo_diag & 0x2000) {
+		    /* Rx underrun */
+		    wait_for_completion(dev, RxReset);
+		    set_multicast_list(dev);
+		    outw(RxEnable, ioaddr + EL3_CMD);
+		}
+		outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+	    }
+	}
+	
+	if (++i > 10) {
+	    printk(KERN_NOTICE "%s: infinite loop in interrupt, "
+		   "status %4.4x.\n", dev->name, status);
+	    /* Clear all interrupts */
+	    outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+	    break;
+	}
+	/* Acknowledge the IRQ. */
+	outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+    }
+
+    lp->last_irq = jiffies;
+#ifdef PCMCIA_DEBUG
+    DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
+	  dev->name, inw(ioaddr + EL3_STATUS));
+    dev->interrupt = 0;
+#endif
+    return;
+}
+
+static void media_check(u_long arg)
+{
+    struct net_device *dev = (struct net_device *)(arg);
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    int ioaddr = dev->base_addr;
+    u_short media, errs;
+    u_long flags;
+
+    if (dev->start == 0) goto reschedule;
+    
+    EL3WINDOW(1);
+    /* Check for pending interrupt with expired latency timer: with
+       this, we can limp along even if the interrupt is blocked */
+    if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
+	(inb(ioaddr + EL3_TIMER) == 0xff)) {
+	if (!lp->fast_poll)
+	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+	el3_interrupt(dev->irq, dev, NULL);
+	lp->fast_poll = HZ;
+    }
+    if (lp->fast_poll) {
+	lp->fast_poll--;
+	lp->media.expires = jiffies + 2;
+	add_timer(&lp->media);
+	return;
+    }
+    
+    save_flags(flags);
+    cli();
+    EL3WINDOW(4);
+    media = inw(ioaddr+WN4_MEDIA) & 0xc810;
+
+    /* Ignore collisions unless we've had no irq's recently */
+    if (jiffies - lp->last_irq < HZ) {
+	media &= ~0x0010;
+    } else {
+	/* Try harder to detect carrier errors */
+	EL3WINDOW(6);
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	errs = inb(ioaddr + 0);
+	outw(StatsEnable, ioaddr + EL3_CMD);
+	lp->stats.tx_carrier_errors += errs;
+	if (errs) media |= 0x0010;
+    }
+    if (media != lp->media_status) {
+	if ((media & lp->media_status & 0x8000) &&
+	    ((lp->media_status ^ media) & 0x0800))
+	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
+		   (lp->media_status & 0x0800 ? "lost" : "found"));
+	else if ((media & lp->media_status & 0x4000) &&
+		 ((lp->media_status ^ media) & 0x0010))
+	    printk(KERN_INFO "%s: cable %s\n", dev->name,
+		   (lp->media_status & 0x0010 ? "fixed" : "problem"));
+	if (dev->if_port == 0) {
+	    if (media & 0x8000) {
+		if (media & 0x0800)
+		    printk(KERN_INFO "%s: flipped to 10baseT\n",
+			   dev->name);
+		else
+		    tc589_set_xcvr(dev, 2);
+	    }
+	    if (media & 0x4000) {
+		if (media & 0x0010)
+		    tc589_set_xcvr(dev, 1);
+		else
+		    printk(KERN_INFO "%s: flipped to 10base2\n",
+			   dev->name);
+	    }
+	}
+	lp->media_status = media;
+    }
+    
+    EL3WINDOW(1);
+    restore_flags(flags);
+
+reschedule:
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+}
+
+static struct net_device_stats *el3_get_stats(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    unsigned long flags;
+    dev_link_t *link;
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (DEV_OK(link)) {
+	save_flags(flags);
+	cli();
+	update_stats(dev->base_addr, dev);
+	restore_flags(flags);
+    }
+    return &lp->stats;
+}
+
+/*
+  Update statistics.  We change to register window 6, so this should be run
+  single-threaded if the device is active. This is expected to be a rare
+  operation, and it's simpler for the rest of the driver to assume that
+  window 1 is always valid rather than use a special window-state variable.
+*/
+static void update_stats(int ioaddr, struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    
+    DEBUG(2, "%s: updating the statistics.\n", dev->name);
+    /* Turn off statistics updates while reading. */
+    outw(StatsDisable, ioaddr + EL3_CMD);
+    /* Switch to the stats window, and read everything. */
+    EL3WINDOW(6);
+    lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);
+    lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
+    /* Multiple collisions. */	   	inb(ioaddr + 2);
+    lp->stats.collisions		+= inb(ioaddr + 3);
+    lp->stats.tx_window_errors		+= inb(ioaddr + 4);
+    lp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
+    lp->stats.tx_packets		+= inb(ioaddr + 6);
+    /* Rx packets   */			inb(ioaddr + 7);
+    /* Tx deferrals */			inb(ioaddr + 8);
+    inw(ioaddr + 10);	/* Total Rx and Tx octets. */
+    inw(ioaddr + 12);
+    
+    /* Back to window 1, and turn statistics back on. */
+    EL3WINDOW(1);
+    outw(StatsEnable, ioaddr + EL3_CMD);
+}
+
+static int el3_rx(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    int ioaddr = dev->base_addr;
+    int worklimit = 32;
+    short rx_status;
+    
+    DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
+	  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
+    while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
+	   (--worklimit >= 0)) {
+	if (rx_status & 0x4000) { /* Error, update stats. */
+	    short error = rx_status & 0x3800;
+	    lp->stats.rx_errors++;
+	    switch (error) {
+	    case 0x0000:		lp->stats.rx_over_errors++; break;
+	    case 0x0800:		lp->stats.rx_length_errors++; break;
+	    case 0x1000:		lp->stats.rx_frame_errors++; break;
+	    case 0x1800:		lp->stats.rx_length_errors++; break;
+	    case 0x2000:		lp->stats.rx_frame_errors++; break;
+	    case 0x2800:		lp->stats.rx_crc_errors++; break;
+	    }
+	} else {
+	    short pkt_len = rx_status & 0x7ff;
+	    struct sk_buff *skb;
+	    
+	    skb = dev_alloc_skb(pkt_len+5);
+	    
+	    DEBUG(3, "    Receiving packet size %d status %4.4x.\n",
+		  pkt_len, rx_status);
+	    if (skb != NULL) {
+		skb->dev = dev;
+		
+		skb_reserve(skb, 2);
+		insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
+			(pkt_len+3)>>2);
+		skb->protocol = eth_type_trans(skb, dev);
+		
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+		lp->stats.rx_bytes += skb->len;
+	    } else {
+		DEBUG(1, "%s: couldn't allocate a sk_buff of"
+		      " size %d.\n", dev->name, pkt_len);
+		lp->stats.rx_dropped++;
+	    }
+	}
+	/* Pop the top of the Rx FIFO */
+	wait_for_completion(dev, RxDiscard);
+    }
+    if (worklimit == 0)
+	printk(KERN_NOTICE "%s: too much work in el3_rx!\n", dev->name);
+    return 0;
+}
+
+/* Set or clear the multicast filter for this adapter.
+   num_addrs == -1	Promiscuous mode, receive all packets
+   num_addrs == 0	Normal mode, clear multicast list
+   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+    short ioaddr = dev->base_addr;
+    dev_link_t *link;
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (!(DEV_OK(link))) return;
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 2) {
+	static int old = 0;
+	if (old != dev->mc_count) {
+	    old = dev->mc_count;
+	    DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+		  dev->name, old);
+	}
+    }
+#endif
+    if (dev->flags & IFF_PROMISC)
+	outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
+	     ioaddr + EL3_CMD);
+    else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
+	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+    else
+	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+}
+
+static int el3_close(struct net_device *dev)
+{
+    int ioaddr = dev->base_addr;
+    dev_link_t *link;
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (link == NULL)
+	return -ENODEV;
+    
+    DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
+
+    if (DEV_OK(link)) {
+	/* Turn off statistics ASAP.  We update lp->stats below. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	
+	/* Disable the receiver and transmitter. */
+	outw(RxDisable, ioaddr + EL3_CMD);
+	outw(TxDisable, ioaddr + EL3_CMD);
+	
+	if (dev->if_port == 2)
+	    /* Turn off thinnet power.  Green! */
+	    outw(StopCoax, ioaddr + EL3_CMD);
+	else if (dev->if_port == 1) {
+	    /* Disable link beat and jabber */
+	    EL3WINDOW(4);
+	    outw(0, ioaddr + WN4_MEDIA);
+	}
+	
+	/* Switching back to window 0 disables the IRQ. */
+	EL3WINDOW(0);
+	/* But we explicitly zero the IRQ line select anyway. */
+	outw(0x0f00, ioaddr + WN0_IRQ);
+        
+	/* Check if the card still exists */
+	if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
+	    update_stats(ioaddr, dev);
+    }
+
+    link->open--;
+    dev->start = 0;
+    del_timer(&((struct el3_private *)dev->priv)->media);
+    if (link->state & DEV_STALE_CONFIG) {
+	link->release.expires = jiffies + HZ/20;
+	link->state |= DEV_RELEASE_PENDING;
+	add_timer(&link->release);
+    }
+    
+    MOD_DEC_USE_COUNT;
+    
+    return 0;
+}
+
+/*====================================================================*/
+
+int init_3c589_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "3c589_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pcmcia_driver(&dev_info, &tc589_attach, &tc589_detach);
+    return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_3c589_cs();
+}
+
+void cleanup_module(void)
+{
+    DEBUG(0, "3c589_cs: unloading\n");
+    unregister_pcmcia_driver(&dev_info);
+    while (dev_list != NULL)
+	tc589_detach(dev_list);
+}
+#endif
diff -u --recursive --new-file v2.3.17/linux/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- v2.3.17/linux/drivers/net/pcmcia/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/Config.in	Fri Sep 10 10:33:04 1999
@@ -0,0 +1,12 @@
+#
+# PCMCIA Network device configuration
+#
+
+mainmenu_option next_comment
+comment 'PCMCIA network devices'
+
+tristate 'PCMCIA ethernet cards (NE2000 compatibles: DE-650, ...)' CONFIG_PCMCIA_PCNET
+tristate '3Com 3c589 PCMCIA card' CONFIG_PCMCIA_3C589
+tristate 'Aviator/Raytheon 2.4MHz wireless' CONFIG_PCMCIA_RAYCS
+
+endmenu
diff -u --recursive --new-file v2.3.17/linux/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- v2.3.17/linux/drivers/net/pcmcia/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/Makefile	Fri Sep 10 10:33:04 1999
@@ -0,0 +1,40 @@
+#
+# drivers/net/pcmcia/Makefile
+#
+# Makefile for the Linux PCMCIA network device drivers.
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+O_TARGET := pcmcia_net.o
+O_OBJS   :=
+M_OBJS   :=
+MOD_LIST_NAME := NET_MODULES
+
+ifeq ($(CONFIG_PCMCIA_PCNET),y)
+  O_OBJS += pcnet_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_PCNET),m)
+    MX_OBJS += pcnet_cs.o
+  endif
+endif
+
+ifeq ($(CONFIG_PCMCIA_3C589),y)
+  O_OBJS += 3c589_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_3C589),m)
+    MX_OBJS += 3c589_cs.o
+  endif
+endif
+
+ifeq ($(CONFIG_PCMCIA_RAYCS),y)
+  OX_OBJS += ray_cs.o
+else
+  ifeq ($(CONFIG_PCMCIA_RAYCS),m)
+  MX_OBJS += ray_cs.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.17/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
--- v2.3.17/linux/drivers/net/pcmcia/pcnet_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/pcnet_cs.c	Thu Sep  9 17:10:21 1999
@@ -0,0 +1,1359 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for NS8390-based cards
+
+    This driver supports the D-Link DE-650 and Linksys EthernetCard
+    cards, the newer D-Link and Linksys combo cards, Accton EN2212
+    cards, the RPTI EP400, and the PreMax PE-200 in non-shared-memory
+    mode, and the IBM Credit Card Adapter, the NE4100, the Thomas
+    Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory
+    mode.  It will also handle the Socket EA card in either mode.
+
+    Copyright (C) 1998 David A. Hinds -- dhinds@hyper.stanford.edu
+
+    pcnet_cs.c 1.94 1999/07/29 06:04:49
+    
+    The network driver code is based on Donald Becker's NE2000 code:
+
+    Written 1992,1993 by Donald Becker.
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.  This software may be used and
+    distributed according to the terms of the GNU Public License,
+    incorporated herein by reference.
+    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+
+    Based also on Keith Moore's changes to Don Becker's code, for IBM
+    CCAE support.  Drivers merged back together, and shared-memory
+    Socket EA support added, by Ken Raeburn, September 1995.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include "../../drivers/net/8390.h"
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#define PCNET_CMD	0x00
+#define PCNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
+#define PCNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
+#define PCNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
+
+#define PCNET_START_PG	0x40	/* First page of TX buffer */
+#define PCNET_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+/* Socket EA cards have a larger packet buffer */
+#define SOCKET_START_PG	0x01
+#define SOCKET_STOP_PG	0xff
+
+#define PCNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
+
+static char *if_names[] = { "auto", "10baseT", "10base2"};
+
+#define PCMCIA_DEBUG 6
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"pcnet_cs.c 1.94 1999/07/29 06:04:49 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* Transceiver type, for Socket EA and IBM CC cards. */
+static int if_port = 1;
+
+/* Use 64K packet buffer, for Socket EA cards. */
+static int use_big_buf = 1;
+
+/* Shared memory speed, in ns */
+static int mem_speed = 0;
+
+/* Insert a pause in block_output after sending a packet */
+static int delay_output = 0;
+
+/* Length of delay, in microseconds */
+static int delay_time = 4;
+
+/* Use shared memory, if available? */
+static int use_shmem = -1;
+
+/* Ugh!  Let the user hardwire the hardware address for queer cards */
+static int hw_addr[6] = { 0, /* ... */ };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(if_port, "i");
+MODULE_PARM(use_big_buf, "i");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM(delay_output, "i");
+MODULE_PARM(delay_time, "i");
+MODULE_PARM(use_shmem, "i");
+MODULE_PARM(hw_addr, "6i");
+
+/*====================================================================*/
+
+static void pcnet_config(dev_link_t *link);
+static void pcnet_release(u_long arg);
+static int pcnet_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+static int pcnet_open(struct net_device *dev);
+static int pcnet_close(struct net_device *dev);
+
+static void pcnet_reset_8390(struct net_device *dev);
+
+static int set_config(struct net_device *dev, struct ifmap *map);
+
+static int setup_shmem_window(dev_link_t *link, int start_pg,
+			      int stop_pg, int cm_offset);
+static int setup_dma_config(dev_link_t *link, int start_pg,
+			    int stop_pg);
+
+static dev_info_t dev_info = "pcnet_cs";
+
+static dev_link_t *pcnet_attach(void);
+static void pcnet_detach(dev_link_t *);
+
+static dev_link_t *dev_list;
+
+/*====================================================================*/
+
+typedef struct hw_info_t {
+    u_long	offset;
+    u_char	a0, a1, a2;
+    u_long	flags;
+} hw_info_t;
+
+#define DELAY_OUTPUT	0x01
+#define HAS_MISC_REG	0x02
+#define USE_BIG_BUF	0x04
+#define HAS_IBM_MISC	0x08
+#define IS_DL10019A	0x10
+#define USE_SHMEM	0x80	/* autodetected */
+
+static hw_info_t hw_info[] = {
+    { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT }, 
+    { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
+    { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
+    { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
+      DELAY_OUTPUT | HAS_IBM_MISC },
+    { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
+    { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
+    { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
+    { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
+    { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
+    { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
+    { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
+    { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
+    { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
+    { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
+    { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
+    { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
+    { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
+    { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
+    { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45, 
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
+    { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
+    { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
+    { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
+      DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
+    { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
+    { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 }
+};
+
+#define NR_INFO		(sizeof(hw_info)/sizeof(hw_info_t))
+
+static hw_info_t default_info =
+{ /* Unknown NE2000 Clone */ 0x00, 0x00, 0x00, 0x00, 0 };
+static hw_info_t dl_fast_info =
+{ /* D-Link EtherFast */ 0x00, 0x00, 0x00, 0x00, IS_DL10019A };
+
+typedef struct pcnet_dev_t {
+    struct net_device	dev;
+    dev_node_t		node;
+    u_long		flags;
+    caddr_t		base;
+} pcnet_dev_t;
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    pcnet_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    We never need to do anything when a pcnet device is "initialized"
+    by the net software, because we only register already-found cards.
+
+======================================================================*/
+
+static int pcnet_init(struct net_device *dev)
+{
+    return 0;
+}
+
+/*======================================================================
+
+    pcnet_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *pcnet_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    pcnet_dev_t *info;
+    struct net_device *dev;
+    int i, ret;
+
+    DEBUG(0, "pcnet_attach()\n");
+    flush_stale_links();
+
+    /* Create new ethernet device */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &pcnet_release;
+    link->release.data = (u_long)link;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    info = kmalloc(sizeof(struct pcnet_dev_t), GFP_KERNEL);
+    memset(info, 0, sizeof(struct pcnet_dev_t));
+    dev = &info->dev;
+    ethdev_init(dev);
+    dev->name = info->node.dev_name;
+    dev->init = &pcnet_init;
+    dev->open = &pcnet_open;
+    dev->stop = &pcnet_close;
+    dev->set_config = &set_config;
+    dev->tbusy = 1;
+    link->priv = info;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &pcnet_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	pcnet_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* pcnet_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void pcnet_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    long flags;
+
+    DEBUG(0, "pcnet_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    save_flags(flags);
+    cli();
+    if (link->state & DEV_RELEASE_PENDING) {
+	del_timer(&link->release);
+	link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+
+    if (link->state & DEV_CONFIG) {
+	pcnet_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->priv) {
+	struct net_device *dev = link->priv;
+	if (link->dev != NULL)
+	    unregister_netdev(dev);
+	if (dev->priv)
+	    kfree_s(dev->priv, sizeof(struct ei_device));
+	kfree_s(dev, sizeof(struct pcnet_dev_t));
+    }
+    kfree_s(link, sizeof(struct dev_link_t));
+
+} /* pcnet_detach */
+
+/*======================================================================
+
+    For the Linksys EtherFast 10/100 card
+
+======================================================================*/
+
+static hw_info_t *get_dl_fast(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    int i;
+    u_char sum;
+
+    for (sum = 0, i = 0x14; i < 0x1c; i++)
+	sum += inb_p(dev->base_addr + i);
+    if (sum != 0xff)
+	return NULL;
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i);
+    return &dl_fast_info;
+}
+
+/*======================================================================
+
+    This probes for a card's hardware address, for card types that
+    encode this information in their CIS.
+
+======================================================================*/
+
+static hw_info_t *get_hwinfo(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    win_req_t req;
+    memreq_t mem;
+    u_char *base, *virt;
+    int i, j;
+
+    /* Allocate a small memory window */
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0;
+    req.AccessSpeed = 0;
+    link->win = (window_handle_t)link->handle;
+    i = CardServices(RequestWindow, &link->win, &req);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestWindow, i);
+	return NULL;
+    }
+
+    virt = ioremap(req.Base, req.Size);
+    mem.Page = 0;
+    for (i = 0; i < NR_INFO; i++) {
+	mem.CardOffset = hw_info[i].offset & ~(req.Size-1);
+	CardServices(MapMemPage, link->win, &mem);
+	base = &virt[hw_info[i].offset & (req.Size-1)];
+	if ((readb(base+0) == hw_info[i].a0) &&
+	    (readb(base+2) == hw_info[i].a1) &&
+	    (readb(base+4) == hw_info[i].a2))
+	    break;
+    }
+    if (i < NR_INFO) {
+	for (j = 0; j < 6; j++)
+	    dev->dev_addr[j] = readb(base + (j<<1));
+    }
+    
+    iounmap(virt);
+    j = CardServices(ReleaseWindow, link->win);
+    if (j != CS_SUCCESS)
+	cs_error(link->handle, ReleaseWindow, j);
+    return (i < NR_INFO) ? hw_info+i : NULL;
+} /* get_hwinfo */
+
+/*======================================================================
+
+    This probes for a card's hardware address by reading the PROM.
+    It checks the address against a list of known types, then falls
+    back to a simple NE2000 clone signature check.
+
+======================================================================*/
+
+static hw_info_t *get_prom(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    unsigned char prom[32];
+    int i, j, ioaddr;
+
+    /* This is lifted straight from drivers/net/ne.c */
+    struct {
+	unsigned char value, offset;
+    } program_seq[] = {
+	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+	{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
+	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
+	{0x00,	EN0_RCNTHI},
+	{0x00,	EN0_IMR},	/* Mask completion irq. */
+	{0xFF,	EN0_ISR},
+	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
+	{32,	EN0_RCNTLO},
+	{0x00,	EN0_RCNTHI},
+	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
+	{0x00,	EN0_RSARHI},
+	{E8390_RREAD+E8390_START, E8390_CMD},
+    };
+
+    ioaddr = dev->base_addr;
+
+    pcnet_reset_8390(dev);
+    udelay(10000);
+
+    for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+    for (i = 0; i < 32; i++)
+	prom[i] = inb(ioaddr + PCNET_DATAPORT);
+    for (i = 0; i < NR_INFO; i++) {
+	if ((prom[0] == hw_info[i].a0) &&
+	    (prom[2] == hw_info[i].a1) &&
+	    (prom[4] == hw_info[i].a2))
+	    break;
+    }
+    if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
+	for (j = 0; j < 6; j++)
+	    dev->dev_addr[j] = prom[j<<1];
+	return (i < NR_INFO) ? hw_info+i : &default_info;
+    }
+    return NULL;
+} /* get_prom */
+
+/*======================================================================
+
+    This should be totally unnecessary... but when we can't figure
+    out the hardware address any other way, we'll let the user hard
+    wire it when the module is initialized.
+
+======================================================================*/
+
+static hw_info_t *get_hwired(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    int i;
+
+    for (i = 0; i < 6; i++)
+	if (hw_addr[i] != 0) break;
+    if (i == 6)
+	return NULL;
+
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = hw_addr[i];
+
+    return &default_info;
+} /* get_hwired */
+
+/*======================================================================
+
+    pcnet_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static int try_io_port(dev_link_t *link)
+{
+    int j, ret;
+    if (link->io.NumPorts1 == 32) {
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	if (link->io.NumPorts2 > 0) {
+	    /* for master/slave multifunction cards */
+	    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	    link->irq.Attributes = 
+		IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+	}
+    } else {
+	/* This should be two 16-port windows */
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+    }
+    if (link->io.BasePort1 == 0) {
+	for (j = 0; j < 0x400; j += 0x20) {
+	    link->io.BasePort1 = j ^ 0x300;
+	    link->io.BasePort2 = (j ^ 0x300) + 0x10;
+	    ret = CardServices(RequestIO, link->handle, &link->io);
+	    if (ret == CS_SUCCESS) return ret;
+	}
+	return ret;
+    } else {
+	return CardServices(RequestIO, link->handle, &link->io);
+    }
+}
+
+static void pcnet_config(dev_link_t *link)
+{
+    client_handle_t handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    pcnet_dev_t *info;
+    struct net_device *dev;
+    int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
+    int manfid = 0, prodid = 0, has_shmem = 0;
+    u_short buf[64];
+    hw_info_t *hw_info;
+
+    handle = link->handle;
+    info = link->priv;
+    dev = &info->dev;
+
+    DEBUG(0, "pcnet_config(0x%p)\n", link);
+
+    tuple.Attributes = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    tuple.DesiredTuple = CISTPL_MANFID;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
+ 	(CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) {
+	manfid = le16_to_cpu(buf[0]);
+	prodid = le16_to_cpu(buf[1]);
+    }
+    
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (last_ret == CS_SUCCESS) {
+	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+	cistpl_io_t *io = &(parse.cftable_entry.io);
+	
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+	if ((cfg->index == 0) || (cfg->io.nwin == 0))
+	    goto next_entry;
+	
+	link->conf.ConfigIndex = cfg->index;
+	/* For multifunction cards, by convention, we configure the
+	   network function with window 0, and serial with window 1 */
+	if (io->nwin > 1) {
+	    i = (io->win[1].len > io->win[0].len);
+	    link->io.BasePort2 = io->win[1-i].base;
+	    link->io.NumPorts2 = io->win[1-i].len;
+	} else {
+	    i = link->io.NumPorts2 = 0;
+	}
+	has_shmem = ((cfg->mem.nwin == 1) &&
+		     (cfg->mem.win[0].len >= 0x4000));
+	link->io.BasePort1 = io->win[i].base;
+	link->io.NumPorts1 = io->win[i].len;
+	if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
+	    last_ret = try_io_port(link);
+	    if (last_ret == CS_SUCCESS) break;
+	}
+    next_entry:
+	last_ret = CardServices(GetNextTuple, handle, &tuple);
+    }
+    if (last_ret != CS_SUCCESS) {
+	cs_error(handle, RequestIO, last_ret);
+	goto failed;
+    }
+
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    
+    if (link->io.NumPorts2 == 8) {
+	link->conf.Attributes |= CONF_ENABLE_SPKR;
+	link->conf.Status = CCSR_AUDIO_ENA;
+    }
+    if ((manfid == MANFID_IBM) &&
+	(prodid == PRODID_IBM_HOME_AND_AWAY))
+	link->conf.ConfigIndex |= 0x10;
+    
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if ((if_port == 1) || (if_port == 2))
+	dev->if_port = if_port;
+    else
+	printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n");
+    dev->tbusy = 0;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
+	goto failed;
+    }
+
+    hw_info = get_hwinfo(link);
+    if (hw_info == NULL)
+	hw_info = get_prom(link);
+    if (hw_info == NULL)
+	hw_info = get_dl_fast(link);
+    if (hw_info == NULL)
+	hw_info = get_hwired(link);
+    
+    if (hw_info == NULL) {
+	printk(KERN_NOTICE "pcnet_cs: unable to read hardware net address\n");
+	goto config_undo;
+    }
+
+    info->flags = hw_info->flags;
+    /* Check for user overrides */
+    info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
+    if ((manfid == MANFID_SOCKET) && (prodid == PRODID_SOCKET_LPE))
+	info->flags &= ~USE_BIG_BUF;
+    if (!use_big_buf)
+	info->flags &= ~USE_BIG_BUF;
+    
+    if (info->flags & USE_BIG_BUF) {
+	start_pg = SOCKET_START_PG;
+	stop_pg = SOCKET_STOP_PG;
+	cm_offset = 0x10000;
+    } else {
+	start_pg = PCNET_START_PG;
+	stop_pg = PCNET_STOP_PG;
+	cm_offset = 0;
+    }
+
+    /* has_shmem is ignored if use_shmem != -1 */
+    if ((use_shmem == 0) || (!has_shmem && (use_shmem == -1)) ||
+	(setup_shmem_window(link, start_pg, stop_pg, cm_offset) != 0))
+	setup_dma_config(link, start_pg, stop_pg);
+
+    ei_status.name = "NE2000";
+    ei_status.word16 = 1;
+    ei_status.reset_8390 = &pcnet_reset_8390;
+
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    printk(KERN_INFO "%s: NE2000 Compatible: io %#3lx, irq %d,",
+	   dev->name, dev->base_addr, dev->irq);
+    if (info->flags & USE_SHMEM)
+	printk (" mem %#5lx,", dev->mem_start);
+    if (info->flags & HAS_MISC_REG)
+	printk(" %s xcvr,", if_names[dev->if_port]);
+    printk(" hw_addr ");
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    return;
+
+config_undo:
+    unregister_netdev(dev);
+    goto failed;
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    pcnet_release((u_long)link);
+    return;
+} /* pcnet_config */
+
+/*======================================================================
+
+    After a card is removed, pcnet_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void pcnet_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    pcnet_dev_t *info = link->priv;
+
+    DEBUG(0, "pcnet_release(0x%p)\n", link);
+
+    if (link->open) {
+	DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n",
+	      info->node.dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    if (info->flags & USE_SHMEM) {
+	iounmap(info->base);
+	CardServices(ReleaseWindow, link->win);
+    }
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+    link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
+
+} /* pcnet_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+======================================================================*/
+
+static int pcnet_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    pcnet_dev_t *info = link->priv;
+
+    DEBUG(2, "pcnet_event(0x%06x)\n", event);
+
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    info->dev.tbusy = 1; info->dev.start = 0;
+	    link->release.expires = jiffies + HZ/20;
+	    link->state |= DEV_RELEASE_PENDING;
+	    add_timer(&link->release);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT;
+	pcnet_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (link->open) {
+		info->dev.tbusy = 1; info->dev.start = 0;
+	    }
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		pcnet_reset_8390(&info->dev);
+		NS8390_init(&info->dev, 1);
+		info->dev.tbusy = 0; info->dev.start = 1;
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* pcnet_event */
+
+/*====================================================================*/
+
+static void set_misc_reg(struct net_device *dev)
+{
+    int nic_base = dev->base_addr;
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+    u_char tmp;
+    
+    if (info->flags & HAS_MISC_REG) {
+	tmp = inb_p(nic_base + PCNET_MISC) & ~3;
+	if (dev->if_port == 2)
+	    tmp |= 1;
+	if (info->flags & USE_BIG_BUF)
+	    tmp |= 2;
+	if (info->flags & HAS_IBM_MISC)
+	    tmp |= 8;
+	outb_p(tmp, nic_base + PCNET_MISC);
+    }
+}
+
+/*====================================================================*/
+
+static int pcnet_open(struct net_device *dev)
+{
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+    dev_link_t *link;
+    
+    DEBUG(2, "pcnet_open('%s')\n", dev->name);
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    /* For D-Link EtherFast, wait for something(?) to happen */
+    if (info->flags & IS_DL10019A) {
+	int i;
+	for (i = 0; i < 20; i++) {
+	    if ((inb(dev->base_addr+0x1c) & 0x01) == 0) break;
+	    current->state = TASK_INTERRUPTIBLE;
+	    schedule_timeout(HZ/10);
+	}
+    }
+    
+    set_misc_reg(dev);
+    request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev_info, dev);
+    return ei_open(dev);
+} /* pcnet_open */
+
+/*====================================================================*/
+
+static int pcnet_close(struct net_device *dev)
+{
+    dev_link_t *link;
+
+    DEBUG(2, "pcnet_close('%s')\n", dev->name);
+
+    for (link = dev_list; link; link = link->next)
+	if (link->priv == dev) break;
+    if (link == NULL)
+	return -ENODEV;
+    free_irq(dev->irq, dev);
+    
+    link->open--; dev->start = 0;
+    if (link->state & DEV_STALE_CONFIG) {
+	link->release.expires = jiffies+HZ/20;
+	link->state |= DEV_RELEASE_PENDING;
+	add_timer(&link->release);
+    }
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+} /* pcnet_close */
+
+/*======================================================================
+
+    Hard reset the card.  This used to pause for the same period that
+    a 8390 reset command required, but that shouldn't be necessary.
+
+======================================================================*/
+
+static void pcnet_reset_8390(struct net_device *dev)
+{
+    int nic_base = dev->base_addr;
+    int i;
+
+    ei_status.txing = ei_status.dmaing = 0;
+
+    outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);
+
+    for (i = 0; i < 100; i++) {
+	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
+	    break;
+	udelay(100L);
+    }
+    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
+    
+    if (i == 100)
+	printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n",
+	       dev->name);
+    set_misc_reg(dev);
+    
+} /* pcnet_reset_8390 */
+
+/* ======================================================================= */
+
+static int set_config(struct net_device *dev, struct ifmap *map)
+{
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+	if ((map->port != 0) && !(info->flags & HAS_MISC_REG)) {
+	    printk(KERN_NOTICE "%s: transceiver selection not "
+		   "implemented\n", dev->name);
+	    return -EINVAL;
+	}
+	if ((map->port == 1) || (map->port == 2)) {
+	    dev->if_port = map->port;
+	    printk(KERN_INFO "%s: switched to %s port\n",
+		   dev->name, if_names[dev->if_port]);
+	} else
+	    return -EINVAL;
+    }
+    return 0;
+}
+
+/* ======================================================================= */
+
+static void dma_get_8390_hdr(struct net_device *dev,
+			     struct e8390_pkt_hdr *hdr,
+			     int ring_page)
+{
+    int nic_base = dev->base_addr;
+
+    if (ei_status.dmaing) {
+	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+	       "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n",
+	       dev->name, ei_status.dmaing, ei_status.irqlock,
+	       (long)dev->interrupt);
+	return;
+    }
+    
+    ei_status.dmaing |= 0x01;
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
+    outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+    outb_p(0, nic_base + EN0_RCNTHI);
+    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
+    outb_p(ring_page, nic_base + EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
+
+    insw(nic_base + PCNET_DATAPORT, hdr,
+	    sizeof(struct e8390_pkt_hdr)>>1);
+    /* Fix for big endian systems */
+    hdr->count = le16_to_cpu(hdr->count);
+
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+}
+
+/* ======================================================================= */
+
+static void dma_block_input(struct net_device *dev, int count,
+			    struct sk_buff *skb, int ring_offset)
+{
+    int nic_base = dev->base_addr;
+    int xfer_count = count;
+    char *buf = skb->data;
+
+#ifdef PCMCIA_DEBUG
+    if ((ei_debug > 4) && (count != 4))
+	printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4);
+#endif
+    if (ei_status.dmaing) {
+	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+	       "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n",
+	       dev->name, ei_status.dmaing, ei_status.irqlock,
+	       (long)dev->interrupt);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
+    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+    outb_p(count >> 8, nic_base + EN0_RCNTHI);
+    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
+
+    insw(nic_base + PCNET_DATAPORT,buf,count>>1);
+    if (count & 0x01)
+	buf[count-1] = inb(nic_base + PCNET_DATAPORT), xfer_count++;
+
+    /* This was for the ALPHA version only, but enough people have
+       encountering problems that it is still here. */
+#ifdef PCMCIA_DEBUG
+    if (ei_debug > 4) {		/* DMA termination address check... */
+	int addr, tries = 20;
+	do {
+	    /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
+	       -- it's broken for Rx on some cards! */
+	    int high = inb_p(nic_base + EN0_RSARHI);
+	    int low = inb_p(nic_base + EN0_RSARLO);
+	    addr = (high << 8) + low;
+	    if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff))
+		break;
+	} while (--tries > 0);
+	if (tries <= 0)
+	    printk(KERN_NOTICE "%s: RX transfer address mismatch,"
+		   "%#4.4x (expected) vs. %#4.4x (actual).\n",
+		   dev->name, ring_offset + xfer_count, addr);
+    }
+#endif
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+} /* dma_block_input */
+
+/*====================================================================*/
+
+static void dma_block_output(struct net_device *dev, int count,
+			     const unsigned char *buf,
+			     const int start_page)
+{
+    int nic_base = dev->base_addr;
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+#ifdef PCMCIA_DEBUG
+    int retries = 0;
+#endif
+    u_long dma_start;
+
+#ifdef PCMCIA_DEBUG
+    if (ei_debug > 4)
+	printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count);
+#endif
+
+    /* Round the count up for word writes.  Do we need to do this?
+       What effect will an odd byte count have on the 8390?
+       I should check someday. */
+    if (count & 0x01)
+	count++;
+    if (ei_status.dmaing) {
+	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output."
+	       "[DMAstat:%1x][irqlock:%1x][intr:%ld]\n",
+	       dev->name, ei_status.dmaing, ei_status.irqlock,
+	       (long)dev->interrupt);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    /* We should already be in page 0, but to be safe... */
+    outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD);
+
+#ifdef PCMCIA_DEBUG
+  retry:
+#endif
+
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);
+
+    /* Now the normal output. */
+    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+    outb_p(count >> 8,   nic_base + EN0_RCNTHI);
+    outb_p(0x00, nic_base + EN0_RSARLO);
+    outb_p(start_page, nic_base + EN0_RSARHI);
+
+    outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD);
+    outsw(nic_base + PCNET_DATAPORT, buf, count>>1);
+
+    dma_start = jiffies;
+
+#ifdef PCMCIA_DEBUG
+    /* This was for the ALPHA version only, but enough people have
+       encountering problems that it is still here. */
+    if (ei_debug > 4) {	/* DMA termination address check... */
+	int addr, tries = 20;
+	do {
+	    int high = inb_p(nic_base + EN0_RSARHI);
+	    int low = inb_p(nic_base + EN0_RSARLO);
+	    addr = (high << 8) + low;
+	    if ((start_page << 8) + count == addr)
+		break;
+	} while (--tries > 0);
+	if (tries <= 0) {
+	    printk(KERN_NOTICE "%s: Tx packet transfer address mismatch,"
+		   "%#4.4x (expected) vs. %#4.4x (actual).\n",
+		   dev->name, (start_page << 8) + count, addr);
+	    if (retries++ == 0)
+		goto retry;
+	}
+    }
+#endif
+
+    while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+	if (jiffies - dma_start > PCNET_RDC_TIMEOUT) {
+	    printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",
+		   dev->name);
+	    pcnet_reset_8390(dev);
+	    NS8390_init(dev, 1);
+	    break;
+	}
+
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+    if (info->flags & DELAY_OUTPUT)
+	udelay((long)delay_time);
+    ei_status.dmaing &= ~0x01;
+}
+
+/*====================================================================*/
+
+static int setup_dma_config(dev_link_t *link, int start_pg,
+			    int stop_pg)
+{
+    struct net_device *dev = link->priv;
+
+    ei_status.tx_start_page = start_pg;
+    ei_status.rx_start_page = start_pg + TX_PAGES;
+    ei_status.stop_page = stop_pg;
+
+    /* set up block i/o functions */
+    ei_status.get_8390_hdr = &dma_get_8390_hdr;
+    ei_status.block_input = &dma_block_input;
+    ei_status.block_output = &dma_block_output;
+
+    return 0;
+}
+
+/*====================================================================*/
+
+static void copyin(unsigned char *dest, unsigned char *src, int c)
+{
+    unsigned short *d = (unsigned short *) dest;
+    unsigned short *s = (unsigned short *) src;
+    int odd;
+
+    if (c <= 0)
+	return;
+    odd = (c & 01); c >>= 1;
+
+    if (c) {
+	do { *d++ = readw(s++); } while (--c);
+    }
+    /* get last byte by fetching a word and masking */
+    if (odd)
+	*((unsigned char *)d) = readw(s) & 0xff;
+}
+
+static void copyout(unsigned char *dest, const unsigned char *src, int c)
+{
+    volatile unsigned short *d = (unsigned short *) dest;
+    unsigned short *s = (unsigned short *) src;
+    int odd;
+
+    if (c <= 0)
+	return;
+    odd = (c & 01); c >>= 1;
+
+    if (c) {
+	do { writew(*s++, d++); } while (--c);
+    }
+    /* copy last byte doing a read-modify-write */
+    if (odd)
+	writew((readw(d) & 0xff00) | *(u_char *)s, d);
+}
+
+/*====================================================================*/
+
+static void shmem_get_8390_hdr(struct net_device *dev,
+			       struct e8390_pkt_hdr *hdr,
+			       int ring_page)
+{
+    void *xfer_start = (void *)(dev->rmem_start + (ring_page << 8)
+				- (ei_status.rx_start_page << 8));
+    
+    copyin((void *)hdr, xfer_start, sizeof(struct e8390_pkt_hdr));
+    /* Fix for big endian systems */
+    hdr->count = le16_to_cpu(hdr->count);
+}
+
+/*====================================================================*/
+
+static void shmem_block_input(struct net_device *dev, int count,
+			      struct sk_buff *skb, int ring_offset)
+{
+    void *xfer_start = (void *)(dev->rmem_start + ring_offset
+				- (ei_status.rx_start_page << 8));
+    char *buf = skb->data;
+    
+    if (xfer_start + count > (void *)dev->rmem_end) {
+	/* We must wrap the input move. */
+	int semi_count = (void*)dev->rmem_end - xfer_start;
+	copyin(buf, xfer_start, semi_count);
+	buf += semi_count;
+	ring_offset = ei_status.rx_start_page << 8;
+	xfer_start = (void *)dev->rmem_start;
+	count -= semi_count;
+    }
+    copyin(buf, xfer_start, count);
+}
+
+/*====================================================================*/
+
+static void shmem_block_output(struct net_device *dev, int count,
+			       const unsigned char *buf,
+			       const int start_page)
+{
+    void *shmem = (void *)dev->mem_start + (start_page << 8);
+    shmem -= ei_status.tx_start_page << 8;
+
+    if (ei_debug > 4)
+	printk(KERN_DEBUG "[bo=%d @ %x]\n", count, start_page);
+
+    copyout(shmem, buf, count);
+}
+
+/*====================================================================*/
+
+static int setup_shmem_window(dev_link_t *link, int start_pg,
+			      int stop_pg, int cm_offset)
+{
+    struct net_device *dev = link->priv;
+    pcnet_dev_t *info = link->priv;
+    win_req_t req;
+    memreq_t mem;
+    int i, window_size, offset, last_ret, last_fn;
+
+    window_size = (stop_pg - start_pg) << 8;
+    if (window_size > 32 * 1024)
+	window_size = 32 * 1024;
+
+    /* Make sure it's a power of two.  */
+    while ((window_size & (window_size - 1)) != 0)
+	window_size += window_size & ~(window_size - 1);
+
+    /* Allocate a memory window */
+    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Attributes |= WIN_USE_WAIT;
+    req.Base = 0; req.Size = window_size;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+
+    mem.CardOffset = (start_pg << 8) + cm_offset;
+    offset = mem.CardOffset % window_size;
+    mem.CardOffset -= offset;
+    mem.Page = 0;
+    CS_CHECK(MapMemPage, link->win, &mem);
+
+    /* Try scribbling on the buffer */
+    info->base = ioremap(req.Base, window_size);
+    for (i = 0; i < (TX_PAGES<<8); i += 2)
+	writew((i>>1), info->base+offset+i);
+    udelay(100);
+    for (i = 0; i < (TX_PAGES<<8); i += 2)
+	if (readw(info->base+offset+i) != (i>>1)) break;
+    pcnet_reset_8390(dev);
+    if (i != (TX_PAGES<<8)) {
+	iounmap(info->base);
+	CardServices(ReleaseWindow, link->win);
+	info->base = NULL; link->win = NULL;
+	goto failed;
+    }
+    
+    dev->mem_start = (u_long)info->base + offset;
+    dev->rmem_start = dev->mem_start + (TX_PAGES<<8);
+    dev->mem_end = dev->rmem_end = (u_long)info->base + req.Size;
+
+    ei_status.tx_start_page = start_pg;
+    ei_status.rx_start_page = start_pg + TX_PAGES;
+    ei_status.stop_page = start_pg + ((req.Size - offset) >> 8);
+
+    /* set up block i/o functions */
+    ei_status.get_8390_hdr = &shmem_get_8390_hdr;
+    ei_status.block_input = &shmem_block_input;
+    ei_status.block_output = &shmem_block_output;
+
+    info->flags |= USE_SHMEM;
+    return 0;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    return 1;
+}
+
+/*====================================================================*/
+
+#ifdef MODULE
+int init_module(void)
+#else
+int init_pcnet_cs(void)
+#endif
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "pcnet_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pcmcia_driver(&dev_info, &pcnet_attach, &pcnet_detach);
+    DEBUG(0, "pcnet driver registered\n" );
+    return 0;
+}
+
+//__initcall(init_pcnet_cs);
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+    DEBUG(0, "pcnet_cs: unloading\n");
+    unregister_pcmcia_driver(&dev_info);
+    while (dev_list != NULL)
+	pcnet_detach(dev_list);
+}
+#endif
diff -u --recursive --new-file v2.3.17/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c
--- v2.3.17/linux/drivers/net/pcmcia/ray_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/ray_cs.c	Thu Sep  9 22:19:10 1999
@@ -0,0 +1,2348 @@
+/*=============================================================================
+ *
+ * A  PCMCIA client driver for the Raylink wireless LAN card.
+ * The starting point for this module was the skeleton.c in the
+ * PCMCIA 2.9.12 package written by David Hinds, dhinds@allegro.stanford.edu
+ *
+ *
+ * Copyright (c) 1998  Corey Thomas (corey@world.std.com)
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 only of the GNU General Public License as 
+ * published by the Free Software Foundation.
+ *
+ * It 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
+ * 
+=============================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+
+#include "rayctl.h"
+#include "ray_cs.h"
+
+/* All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+
+   I found that  adding -DPCMCIA_DEBUG to the compile options during
+   the 'make config' resulted in cardmgr not finding any sockets.
+   Therefore, this module uses RAYLINK_DEBUG instead.
+   The module option to use is ray_debug=#
+    where # is 1 for modest output
+               2 for more output
+               ...
+*/
+
+#ifdef RAYLINK_DEBUG
+static int ray_debug = RAYLINK_DEBUG;
+MODULE_PARM(ray_debug, "i");
+/* #define DEBUG(n, args...) if (ray_debug>(n)) printk(KERN_DEBUG args); */
+#define DEBUG(n, args...) if (ray_debug>(n)) printk(args);
+#else
+#define DEBUG(n, args...)
+#endif
+/** Prototypes based on PCMCIA skeleton driver *******************************/
+void ray_config(dev_link_t *link);
+void ray_release(u_long arg);
+int ray_event(event_t event, int priority, event_callback_args_t *args);
+dev_link_t *ray_attach(void);
+void ray_detach(dev_link_t *);
+
+/***** Prototypes indicated by device structure ******************************/
+int ray_dev_close(struct net_device *dev);
+int ray_dev_config(struct net_device *dev, struct ifmap *map);
+struct enet_statistics *ray_get_stats(struct net_device *dev);
+int ray_dev_init(struct net_device *dev);
+int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+int ray_open(struct net_device *dev);
+int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void ray_update_multi_list(struct net_device *dev, int all);
+int encapsulate_frame(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
+                unsigned char *data, int len);
+int translate_frame(ray_dev_t *local, struct tx_msg *ptx,
+                unsigned char *data, int len);
+void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
+                unsigned char *data);
+void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
+
+/***** Prototypes for raylink functions **************************************/
+int asc_to_int(char a);
+void authenticate(ray_dev_t *local);
+int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
+void authenticate_timeout(u_long);
+int get_free_ccs(ray_dev_t *local);
+int get_free_tx_ccs(ray_dev_t *local);
+void init_startup_params(ray_dev_t *local);
+int parse_addr(char *in_str, UCHAR *out);
+int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type);
+int ray_init(struct net_device *dev);
+int interrupt_ecf(ray_dev_t *local, int ccs);
+void ray_reset(struct net_device *dev);
+void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len);
+void verify_dl_startup(u_long);
+
+/* Prototypes for interrpt time functions **********************************/
+void ray_interrupt(int reg, void *dev_id, struct pt_regs *regs);
+void clear_interrupt(ray_dev_t *local);
+void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
+                       unsigned int pkt_addr, int rx_len);
+int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
+void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs);
+void release_frag_chain(ray_dev_t *local, struct rcs *prcs);
+void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
+                     unsigned int pkt_addr, int rx_len);
+void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
+             int rx_len);
+void associate(ray_dev_t *local);
+
+/* Card command functions */
+int dl_startup_params(struct net_device *dev);
+void join_net(u_long local);
+void start_net(u_long local);
+/* void start_net(ray_dev_t *local); */
+
+int ray_cs_proc_read(char *buf, char **start, off_t off, int len, int spare);
+
+/* Create symbol table for registering with kernel in init_module */
+EXPORT_SYMBOL(ray_dev_ioctl);
+EXPORT_SYMBOL(ray_rx);
+
+/*===========================================================================*/
+/* Parameters that can be set with 'insmod' */
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_long irq_mask = 0xdeb8;
+MODULE_PARM(irq_mask,"i");
+
+/* ADHOC=0, Infrastructure=1 */
+static int net_type = ADHOC;
+MODULE_PARM(net_type,"i");
+
+/* Hop dwell time in Kus (1024 us units defined by 802.11) */
+static int hop_dwell = 128;
+MODULE_PARM(hop_dwell,"i");
+
+/* Beacon period in Kus */
+static int beacon_period = 256;
+MODULE_PARM(beacon_period,"i");
+
+/* power save mode (0 = off, 1 = save power) */
+static int psm = 0;
+MODULE_PARM(psm,"i");
+
+/* String for network's Extended Service Set ID. 32 Characters max */
+static char *essid = NULL;
+MODULE_PARM(essid,"s");
+
+/* Default to encapsulation unless translation requested */
+static int translate = 1;
+MODULE_PARM(translate,"i");
+
+static int country = USA;
+MODULE_PARM(country,"i");
+
+static int sniffer = 0;
+MODULE_PARM(sniffer,"i");
+
+static int bc = 0;
+MODULE_PARM(bc,"i");
+
+/* 48 bit physical card address if overriding card's real physical
+ * address is required.  Since IEEE 802.11 addresses are 48 bits
+ * like ethernet, an int can't be used, so a string is used. To
+ * allow use of addresses starting with a decimal digit, the first
+ * character must be a letter and will be ignored. This letter is
+ * followed by up to 12 hex digits which are the address.  If less
+ * than 12 digits are used, the address will be left filled with 0's.
+ * Note that bit 0 of the first byte is the broadcast bit, and evil
+ * things will happen if it is not 0 in a card address.
+ */
+static char *phy_addr = NULL;
+MODULE_PARM(phy_addr,"s");
+
+
+/* The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+static dev_info_t dev_info = "ray_cs";
+
+/* A linked list of "instances" of the ray device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+*/
+static dev_link_t *dev_list = NULL;
+
+/* A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+*/
+static const unsigned int ray_mem_speed = 0x2A;
+
+static UCHAR b5_default_startup_parms[] = {
+    0,   0,                         /* Adhoc station */
+   'L','I','N','U','X', 0,  0,  0,  /* 32 char ESSID */
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    1,  0,                          /* Active scan, CA Mode */
+    0,  0,  0,  0,  0,  0,          /* No default MAC addr  */
+    0x7f, 0xff,                     /* Frag threshold */
+    0x00, 0x80,                     /* Hop time 128 Kus*/
+    0x01, 0x00,                     /* Beacon period 256 Kus */
+    0x01, 0x07, 0xa3,               /* DTIM, retries, ack timeout*/
+    0x1d, 0x82, 0x4e,               /* SIFS, DIFS, PIFS */
+    0x7f, 0xff,                     /* RTS threshold */
+    0x04, 0xe2, 0x38, 0xA4,         /* scan_dwell, max_scan_dwell */
+    0x05,                           /* assoc resp timeout thresh */
+    0x08, 0x02, 0x08,               /* adhoc, infra, super cycle max*/
+    0,                              /* Promiscuous mode */
+    0x0c, 0x0bd,                    /* Unique word */
+    0x32,                           /* Slot time */
+    0xff, 0xff,                     /* roam-low snr, low snr count */
+    0x05, 0xff,                     /* Infra, adhoc missed bcn thresh */
+    0x01, 0x0b, 0x4f,               /* USA, hop pattern, hop pat length */
+/* b4 - b5 differences start here */
+    0x00, 0x3f,                     /* CW max */
+    0x00, 0x0f,                     /* CW min */
+    0x04, 0x08,                     /* Noise gain, limit offset */
+    0x28, 0x28,                     /* det rssi, med busy offsets */
+    7,                              /* det sync thresh */
+    0, 2, 2,                        /* test mode, min, max */
+    0,                              /* allow broadcast SSID probe resp */
+    0, 0,                           /* privacy must start, can join */
+    2, 0, 0, 0, 0, 0, 0, 0          /* basic rate set */
+};
+
+static UCHAR b4_default_startup_parms[] = {
+    0,   0,                         /* Adhoc station */
+   'L','I','N','U','X', 0,  0,  0,  /* 32 char ESSID */
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    1,  0,                          /* Active scan, CA Mode */
+    0,  0,  0,  0,  0,  0,          /* No default MAC addr  */
+    0x7f, 0xff,                     /* Frag threshold */
+    0x02, 0x00,                     /* Hop time */
+    0x00, 0x01,                     /* Beacon period */
+    0x01, 0x07, 0xa3,               /* DTIM, retries, ack timeout*/
+    0x1d, 0x82, 0xce,               /* SIFS, DIFS, PIFS */
+    0x7f, 0xff,                     /* RTS threshold */
+    0xfb, 0x1e, 0xc7, 0x5c,         /* scan_dwell, max_scan_dwell */
+    0x05,                           /* assoc resp timeout thresh */
+    0x04, 0x02, 0x4,                /* adhoc, infra, super cycle max*/
+    0,                              /* Promiscuous mode */
+    0x0c, 0x0bd,                    /* Unique word */
+    0x4e,                           /* Slot time (TBD seems wrong)*/
+    0xff, 0xff,                     /* roam-low snr, low snr count */
+    0x05, 0xff,                     /* Infra, adhoc missed bcn thresh */
+    0x01, 0x0b, 0x4e,               /* USA, hop pattern, hop pat length */
+/* b4 - b5 differences start here */
+    0x3f, 0x0f,                     /* CW max, min */
+    0x04, 0x08,                     /* Noise gain, limit offset */
+    0x28, 0x28,                     /* det rssi, med busy offsets */
+    7,                              /* det sync thresh */
+    0, 2, 2                         /* test mode, min, max*/
+};
+/*===========================================================================*/
+static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0};
+
+static char rcsid[] = " $Id: ray_cs.c,v 1.60 1999/09/01 20:58:45 corey Exp $ - Corey Thomas corey@world.std.com";
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry ray_cs_proc_entry = {
+    0,                         /* Dynamic inode # */
+    6,"ray_cs",                /* name length and name */
+    S_IFREG | S_IRUGO,         /* mode */
+    1, 0, 0,                   /* nlinks, owner, group */
+    0,                         /* size (unused) */
+    NULL,                      /* operations (default) */
+    &ray_cs_proc_read,         /* function to read data */
+    /* The end ?? */
+};
+#endif
+/*===========================================================================*/
+void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+/*=============================================================================
+    ray_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+=============================================================================*/
+dev_link_t *ray_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    ray_dev_t *local;
+    int ret;
+    struct net_device *dev;
+    
+    DEBUG(1, "ray_attach()\n");
+
+    /* Initialize the dev_link_t structure */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &ray_release;
+    link->release.data = (u_long)link;
+
+    /* The io structure describes IO port mapping. None used here */
+    link->io.NumPorts1 = 0;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 5;
+
+    /* Interrupt setup. For PCMCIA, driver takes what's given */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+    link->irq.IRQInfo2 = irq_mask;
+    link->irq.Handler = &ray_interrupt;
+
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Allocate space for private device-specific data */
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    memset(dev, 0, sizeof(struct net_device));
+    link->priv = dev;
+    link->irq.Instance = dev;
+    
+    local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL);
+    memset(local, 0, sizeof(ray_dev_t));
+    dev->priv = local;
+    local->finder = link;
+    link->dev = &local->node;
+    local->card_status = CARD_INSERTED;
+	local->authentication_state = UNAUTHENTICATED;
+    local->num_multi = 0;
+    DEBUG(2,"ray_attach link = %p,  dev = %p,  local = %p, intr = %p\n",
+          link,dev,local,&ray_interrupt);
+
+    /* Raylink entries in the device structure */
+    dev->hard_start_xmit = &ray_dev_start_xmit;
+    dev->set_config = &ray_dev_config;
+    dev->get_stats  = &ray_get_stats;
+    dev->do_ioctl = &ray_dev_ioctl;
+
+    dev->set_multicast_list = &set_multicast_list;
+
+    DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n");
+    ether_setup(dev);
+    dev->name = local->node.dev_name;
+    dev->init = &ray_dev_init;
+    dev->open = &ray_open;
+    dev->stop = &ray_dev_close;
+    dev->tbusy = 1;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ray_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+
+    DEBUG(2,"ray_cs ray_attach calling CardServices(RegisterClient...)\n");
+
+    init_timer(&local->timer);
+
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+        printk("ray_cs ray_attach RegisterClient unhappy - detaching\n");
+        cs_error(link->handle, RegisterClient, ret);
+        ray_detach(link);
+        return NULL;
+    }
+    DEBUG(2,"ray_cs ray_attach ending\n");
+    return link;
+} /* ray_attach */
+/*=============================================================================
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+=============================================================================*/
+void ray_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    struct net_device *dev;
+    long flags;
+
+    DEBUG(1, "ray_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+        if (*linkp == link) break;
+    if (*linkp == NULL)
+        return;
+
+    save_flags(flags);
+    cli();
+    if (link->state & DEV_RELEASE_PENDING) {
+        del_timer(&link->release);
+        link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+
+    /* If the device is currently configured and active, we won't
+      actually delete it yet.  Instead, it is marked so that when
+      the release() function is called, that will trigger a proper
+      detach().
+    */
+    if (link->state & DEV_CONFIG) {
+        ray_release((u_long)link);
+        if(link->state & DEV_STALE_CONFIG) {
+            DEBUG(0,"ray_cs: detach postponed, '%s' "
+              "still locked\n", link->dev->dev_name);
+            link->state |= DEV_STALE_LINK;
+            return;
+        }
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+        CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if (link->priv) {
+        dev = link->priv;
+        if (dev->priv)
+            kfree_s(dev->priv, sizeof(ray_dev_t));
+
+        kfree_s(link->priv, sizeof(struct net_device));
+    }
+    kfree_s(link, sizeof(struct dev_link_t));
+    DEBUG(2,"ray_cs ray_detach ending\n");
+} /* ray_detach */
+/*=============================================================================
+    ray_config() is run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+=============================================================================*/
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+#define MAX_TUPLE_SIZE 80
+void ray_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    int last_fn, last_ret;
+    int i;
+    u_char buf[80];
+    win_req_t req;
+    memreq_t mem;
+    struct net_device *dev = (struct net_device *)link->priv;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+    DEBUG(1, "ray_config(0x%p)\n", link);
+
+    /* This reads the card's CONFIG tuple to find its configuration regs */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = MAX_TUPLE_SIZE;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Now allocate an interrupt line.  Note that this does not
+       actually assign a handler to the interrupt.
+    */
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    dev->irq = link->irq.AssignedIRQ;
+    
+    /* This actually configures the PCMCIA socket -- setting up
+       the I/O windows and the interrupt mapping.
+    */
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+/*** Set up 32k window for shared memory (transmit and control) ************/
+    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+    req.Base = 0;
+    req.Size = 0x8000;
+    req.AccessSpeed = ray_mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+    mem.CardOffset = 0x0000; mem.Page = 0;
+    CS_CHECK(MapMemPage, link->win, &mem);
+    local->sram = (UCHAR *)(ioremap(req.Base,req.Size));
+
+/*** Set up 16k window for shared memory (receive buffer) ***************/
+    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+    req.Base = 0;
+    req.Size = 0x4000;
+    req.AccessSpeed = ray_mem_speed;
+    local->rmem_handle = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &local->rmem_handle, &req);
+    mem.CardOffset = 0x8000; mem.Page = 0;
+    CS_CHECK(MapMemPage, local->rmem_handle, &mem);
+    local->rmem = (UCHAR *)(ioremap(req.Base,req.Size));
+
+/*** Set up window for attribute memory ***********************************/
+    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
+    req.Base = 0;
+    req.Size = 0x1000;
+    req.AccessSpeed = ray_mem_speed;
+    local->amem_handle = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &local->amem_handle, &req);
+    mem.CardOffset = 0x0000; mem.Page = 0;
+    CS_CHECK(MapMemPage, local->amem_handle, &mem);
+    local->amem = (UCHAR *)(ioremap(req.Base,req.Size));
+
+    DEBUG(3,"ray_config sram=%p\n",local->sram);
+    DEBUG(3,"ray_config rmem=%p\n",local->rmem);
+    DEBUG(3,"ray_config amem=%p\n",local->amem);
+    if (ray_init(dev) < 0) {
+        ray_release((u_long)link);
+        return;
+    }
+
+    i = register_netdev(dev);
+    if (i != 0) {
+        printk("ray_config register_netdev() failed\n");
+        ray_release((u_long)link);
+        return;
+    }
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    DEBUG(0, "ray_cs device loaded\n");
+
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+
+    ray_release((u_long)link);
+} /* ray_config */
+/*===========================================================================*/
+int ray_init(struct net_device *dev)
+{
+    int i;
+    UCHAR *p;
+    struct ccs *pccs;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    DEBUG(1, "ray_init(0x%p)\n", dev);
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_init - device not present\n");
+        return -1;
+    }
+
+    local->net_type = net_type;
+    local->sta_type = TYPE_STA;
+
+    /* Copy the startup results to local memory */
+    memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,\
+           sizeof(struct startup_res_6));
+
+    /* Check Power up test status and get mac address from card */
+    if (local->startup_res.startup_word != 0x80) {
+DEBUG(0,"ray_init ERROR card status = %2x\n", local->startup_res.startup_word);
+        local->card_status = CARD_INIT_ERROR;
+        return -1;
+    }
+
+    local->fw_ver = local->startup_res.firmware_version[0];
+    local->fw_bld = local->startup_res.firmware_version[1];
+    local->fw_var = local->startup_res.firmware_version[2];
+    DEBUG(1,"ray_init firmware version %d.%d \n",local->fw_ver, local->fw_bld);
+
+    local->tib_length = 0x20;
+    if ((local->fw_ver == 5) && (local->fw_bld >= 30))
+        local->tib_length = local->startup_res.tib_length;
+    DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length);
+    /* Initialize CCS's to buffer free state */
+    pccs = (struct ccs *)(local->sram + CCS_BASE);
+    for (i=0;  i<NUMBER_OF_CCS;  i++) {
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+    }
+    init_startup_params(local);
+
+    /* copy mac address to startup parameters */
+    if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr))
+    {
+        p = local->sparm.b4.a_mac_addr;
+        DEBUG(1,"ray_cs phy address overridden = %2x %2x %2x %2x %2x %2x\n",\
+              p[0],p[1],p[2],p[3],p[4],p[5]);
+    }
+    else
+    {
+        memcpy(&local->sparm.b4.a_mac_addr,
+               &local->startup_res.station_addr, ADDRLEN);
+        p = local->sparm.b4.a_mac_addr;
+        DEBUG(1,"ray_cs phy addr= %2x %2x %2x %2x %2x %2x\n",\
+              p[0],p[1],p[2],p[3],p[4],p[5]);
+    }
+
+    clear_interrupt(local); /* Clear any interrupt from the card */
+    local->card_status = CARD_AWAITING_PARAM;
+    DEBUG(2,"ray_init ending\n");
+    return 0;
+} /* ray_init */
+/*===========================================================================*/
+/* Download startup parameters to the card and command it to read them       */
+int dl_startup_params(struct net_device *dev)
+{
+    int ccsindex;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    struct ccs *pccs;
+    dev_link_t *link = local->finder;
+
+    DEBUG(1,"dl_startup_params entered\n");
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs dl_startup_params - device not present\n");
+        return -1;
+    }
+    
+    /* Copy parameters to host to ECF area */
+    if (local->fw_ver == 0x55) 
+        memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4,
+               sizeof(struct b4_startup_params));
+    else
+        memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5,
+               sizeof(struct b5_startup_params));
+
+    
+    /* Fill in the CCS fields for the ECF */
+    if ((ccsindex = get_free_ccs(local)) == -1) return -1;
+    local->dl_param_ccs = ccsindex;
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
+    DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(0,"ray dl_startup_params failed - ECF not ready for intr\n");
+        local->card_status = CARD_DL_PARAM_ERROR;
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return -2;
+    }
+    local->card_status = CARD_DL_PARAM;
+    /* Start kernel timer to wait for dl startup to complete. */
+    local->timer.expires = jiffies + HZ/2;
+    local->timer.data = (long)local;
+    local->timer.function = &verify_dl_startup;
+    add_timer(&local->timer);
+    DEBUG(2,"ray_cs dl_startup_params started timer for verify_dl_startup\n");
+    return 0;
+} /* dl_startup_params */
+/*===========================================================================*/
+void init_startup_params(ray_dev_t *local)
+{
+    int i; 
+    static char hop_pattern_length[] = { 1,
+                     USA_HOP_MOD,             EUROPE_HOP_MOD,
+                     JAPAN_HOP_MOD,           KOREA_HOP_MOD,
+                     SPAIN_HOP_MOD,           FRANCE_HOP_MOD,
+                     ISRAEL_HOP_MOD,          AUSTRALIA_HOP_MOD,
+                     JAPAN_TEST_HOP_MOD
+    };
+
+    if (country > JAPAN_TEST) country = USA;
+    else
+        if (country < USA) country = USA;
+    /* structure for hop time and beacon period is defined here using 
+     * New 802.11D6.1 format.  Card firmware is still using old format
+     * until version 6.
+     *    Before                    After
+     *    a_hop_time ms byte        a_hop_time ms byte
+     *    a_hop_time 2s byte        a_hop_time ls byte
+     *    a_hop_time ls byte        a_beacon_period ms byte
+     *    a_beacon_period           a_beacon_period ls byte
+     *
+     *    a_hop_time = uS           a_hop_time = KuS
+     *    a_beacon_period = hops    a_beacon_period = KuS
+     */                             /* 64ms = 010000 */
+    if (local->fw_ver == 0x55)  {
+        memcpy((UCHAR *)&local->sparm.b4, b4_default_startup_parms, 
+               sizeof(struct b4_startup_params));
+        /* Translate sane kus input values to old build 4/5 format */
+        /* i = hop time in uS truncated to 3 bytes */
+        i = (hop_dwell * 1024) & 0xffffff;
+        local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff;
+        local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff;
+        local->sparm.b4.a_beacon_period[0] = 0;
+        local->sparm.b4.a_beacon_period[1] =
+            ((beacon_period/hop_dwell) - 1) & 0xff;
+        local->sparm.b4.a_curr_country_code = country;
+        local->sparm.b4.a_hop_pattern_length = 
+            hop_pattern_length[(int)country] - 1;
+		if (bc)
+		{
+			local->sparm.b4.a_ack_timeout = 0x50;
+			local->sparm.b4.a_sifs = 0x3f;
+		}
+    }
+    else {    /* Version 5 uses real kus values */
+        memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, 
+               sizeof(struct b5_startup_params));
+
+        local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff;
+        local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff;
+        local->sparm.b5.a_beacon_period[0] = (beacon_period >> 8) & 0xff;
+        local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff;
+        if (psm)
+            local->sparm.b5.a_power_mgt_state = 1;
+        local->sparm.b5.a_curr_country_code = country;
+        local->sparm.b5.a_hop_pattern_length = 
+            hop_pattern_length[(int)country];
+    }
+    
+    local->sparm.b4.a_network_type = net_type & 0x01;
+    local->sparm.b4.a_acting_as_ap_status = TYPE_STA;
+
+    if (essid != NULL)
+        strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
+} /* init_startup_params */ 
+/*===========================================================================*/
+void verify_dl_startup(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+    struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs;
+    UCHAR status;
+/*    UCHAR *p = local->sram + HOST_TO_ECF_BASE; */
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs verify_dl_startup - device not present\n");
+        return;
+    }
+#ifdef RAYLINK_DEBUG
+    {
+	int i;
+        DEBUG(2,"verify_dl_startup parameters sent via ccs %d:\n",\
+              local->dl_param_ccs);
+        for (i=0; i<sizeof(struct b5_startup_params); i++)
+        {
+            DEBUG(1," %2x ", readb(local->sram + HOST_TO_ECF_BASE + i));
+        }
+        DEBUG(1,"\n");
+    }
+#endif
+
+    status = readb(&pccs->buffer_status);
+    if (status!= CCS_BUFFER_FREE)
+    {
+        DEBUG(0,"Download startup params failed.  Status = %d\n",status);
+        local->card_status = CARD_DL_PARAM_ERROR;
+        return;
+    }
+    if (local->sparm.b4.a_network_type == ADHOC)
+        start_net((u_long)local);
+    else
+        join_net((u_long)local);
+
+    return;
+} /* end verify_dl_startup */
+/*===========================================================================*/
+/* Command card to start a network */
+void start_net(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+    struct ccs *pccs;
+    int ccsindex;
+    dev_link_t *link = local->finder;
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs start_net - device not present\n");
+        return;
+    }
+    /* Fill in the CCS fields for the ECF */
+    if ((ccsindex = get_free_ccs(local)) == -1) return;
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_START_NETWORK, &pccs->cmd);
+    writeb(0, &pccs->var.start_network.update_param);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray start net failed - card not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return;
+    }
+    local->card_status = CARD_DOING_ACQ;
+    return;
+} /* end start_net */
+/*===========================================================================*/
+/* Command card to join a network */
+void join_net(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+
+    struct ccs *pccs;
+    int ccsindex;
+    dev_link_t *link = local->finder;
+    
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs join_net - device not present\n");
+        return;
+    }
+    /* Fill in the CCS fields for the ECF */
+    if ((ccsindex = get_free_ccs(local)) == -1) return;
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_JOIN_NETWORK, &pccs->cmd);
+    writeb(0, &pccs->var.join_network.update_param);
+    writeb(0, &pccs->var.join_network.net_initiated);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray join net failed - card not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return;
+    }
+    local->card_status = CARD_DOING_ACQ;
+    return;
+}
+/*============================================================================
+    After a card is removed, ray_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+=============================================================================*/
+void ray_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    struct net_device *dev = link->priv; 
+    ray_dev_t *local = dev->priv;
+    int i;
+    
+    DEBUG(1, "ray_release(0x%p)\n", link);
+    /* If the device is currently in use, we won't release until it
+      is actually closed.
+    */
+    if (link->open) {
+        DEBUG(1, "ray_cs: release postponed, '%s' still open\n",
+              link->dev->dev_name);
+        link->state |= DEV_STALE_CONFIG;
+        return;
+    }
+	del_timer(&local->timer);
+    if (link->dev != '\0') unregister_netdev(dev);
+    /* Unlink the device chain */
+    link->dev = NULL;
+
+    iounmap(local->sram);
+    iounmap(local->rmem);
+    iounmap(local->amem);
+    /* Do bother checking to see if these succeed or not */
+    i = CardServices(ReleaseWindow, link->win);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i);
+    i = CardServices(ReleaseWindow, local->amem_handle);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
+    i = CardServices(ReleaseWindow, local->rmem_handle);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
+    i = CardServices(ReleaseConfiguration, link->handle);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i);
+    i = CardServices(ReleaseIRQ, link->handle, &link->irq);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i);
+
+    link->state &= ~DEV_CONFIG;
+    if (link->state & DEV_STALE_LINK) ray_detach(link);
+    DEBUG(2,"ray_release ending\n");
+} /* ray_release */
+/*=============================================================================
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+    When a CARD_REMOVAL event is received, we immediately set a flag
+    to block future accesses to this device.  All the functions that
+    actually access the device should check this flag to make sure
+    the card is still present.
+=============================================================================*/
+int ray_event(event_t event, int priority,
+                     event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    struct net_device *dev = link->priv;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    DEBUG(1, "ray_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+        link->state &= ~DEV_PRESENT;
+        dev->tbusy = 1; dev->start = 0;
+        if (link->state & DEV_CONFIG) {
+            link->release.expires = jiffies + HZ/20;
+            add_timer(&link->release);
+            del_timer(&local->timer);
+        }
+        break;
+    case CS_EVENT_CARD_INSERTION:
+        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+        ray_config(link);
+        break;
+    case CS_EVENT_PM_SUSPEND:
+        link->state |= DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+        if (link->state & DEV_CONFIG) {
+            if (link->open) {
+                dev->tbusy = 1;
+                dev->start = 0;
+            }
+            CardServices(ReleaseConfiguration, link->handle);
+        }
+        break;
+    case CS_EVENT_PM_RESUME:
+        link->state &= ~DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+        if (link->state & DEV_CONFIG) {
+            CardServices(RequestConfiguration, link->handle, &link->conf);
+            if (link->open) {
+                ray_reset(dev);
+                dev->tbusy = 0;
+                dev->start = 1;
+            }
+        }
+        break;
+    }
+    return 0;
+    DEBUG(2,"ray_event ending\n");
+} /* ray_event */
+/*===========================================================================*/
+int ray_dev_init(struct net_device *dev)
+{
+    int i;
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+
+    DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_dev_init - device not present\n");
+        return -1;
+    }
+    /* Download startup parameters */
+    if ( (i = dl_startup_params(dev)) < 0)
+    {
+        DEBUG(0,"ray_dev_init dl_startup_params failed - returns 0x%x/n",i);
+        return -1;
+    }
+    
+    /* copy mac and broadcast addresses to linux device */
+    memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN);
+    memset(dev->broadcast, 0xff, ETH_ALEN);
+
+#ifdef RAYLINK_DEBUG
+    {
+    UCHAR *p;
+    p = (UCHAR *)(local->startup_res.station_addr);
+    DEBUG(1,"ray_dev_init card hardware mac addr = %2x %2x %2x %2x %2x %2x\n",\
+          p[0],p[1],p[2],p[3],p[4],p[5]);
+    }
+#endif
+
+    DEBUG(2,"ray_dev_init ending\n");
+    return 0;
+}
+/*===========================================================================*/
+int ray_dev_config(struct net_device *dev, struct ifmap *map)
+{
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+    /* Dummy routine to satisfy device structure */
+    DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_dev_config - device not present\n");
+        return -1;
+    }
+
+    return 0;
+}
+/*===========================================================================*/
+int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+    short length;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_dev_start_xmit - device not present\n");
+        return -1;
+    }
+    DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev);
+    if (dev->tbusy)
+    {
+        DEBUG(2,"ray_dev_start_xmit busy\n");
+        return 1;
+    }
+    if (local->authentication_state == NEED_TO_AUTH) {
+        DEBUG(0,"ray_cs Sending authentication request.\n");
+        if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) {
+            local->authentication_state = AUTHENTICATED;
+            dev->tbusy = 1;
+            return 1;
+        }
+    }
+
+    length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+    switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) {
+        case XMIT_NO_CCS:
+	    case XMIT_NEED_AUTH:
+            dev->tbusy = 1;
+            return 1;
+        case XMIT_NO_INTR:
+        case XMIT_MSG_BAD:
+        case XMIT_OK:
+        default:
+            dev->trans_start = jiffies;
+            dev_kfree_skb(skb);
+            return 0;
+    }
+    return 0;
+} /* ray_dev_start_xmit */
+/*===========================================================================*/
+int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, 
+                UCHAR msg_type)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    struct ccs *pccs;
+    int ccsindex;
+    int offset;
+    struct tx_msg *ptx; /* Address of xmit buffer in PC space */
+    short int addr;     /* Address of xmit buffer in card space */
+    
+    DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev);
+    if (len + TX_HEADER_LENGTH > TX_BUF_SIZE)
+    {
+        DEBUG(0,"ray_hw_xmit packet to large %d bytes\n",len);
+        return XMIT_MSG_BAD;
+    }
+    if ((ccsindex = get_free_tx_ccs(local)) == -1)
+    {
+        DEBUG(2,"ray_hw_xmit - No free tx ccs\n");
+        dev->tbusy = 1;
+        return XMIT_NO_CCS;
+    }
+    addr = TX_BUF_BASE + (ccsindex << 11);
+
+    if (msg_type == DATA_TYPE) {
+        local->stats.tx_bytes += len;
+        local->stats.tx_packets++;
+    }
+
+    ptx = (struct tx_msg *)(local->sram + addr);
+
+    ray_build_header(local, ptx, msg_type, data);
+    if (translate) {
+        offset = translate_frame(local, ptx, data, len);
+    }
+    else { /* Encapsulate frame */
+        /* TBD TIB length will move address of ptx->var */
+        memcpy( (UCHAR *)&ptx->var, data, len);
+        offset = 0;
+    }
+
+    /* fill in the CCS */
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    len += TX_HEADER_LENGTH + offset;
+    writeb(CCS_TX_REQUEST, &pccs->cmd);
+    writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]);
+    writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]);
+    writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]);
+    writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);
+/* TBD still need psm_cam? */
+    writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode);
+    writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate);
+    writeb(0, &pccs->var.tx_request.antenna);
+    DEBUG(3,"ray_hw_xmit default_tx_rate = 0x%x\n",\
+          local->net_default_tx_rate);
+
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(2,"ray_hw_xmit failed - ECF not ready for intr\n");
+/* TBD very inefficient to copy packet to buffer, and then not
+   send it, but the alternative is to queue the messages and that
+   won't be done for a while.  Maybe set tbusy until a CCS is free?
+*/
+        writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
+        return XMIT_NO_INTR;
+    }
+    return XMIT_OK;
+} /* end ray_hw_xmit */
+/*===========================================================================*/
+int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char *data,
+                    int len)
+{
+    unsigned short int proto = ((struct ethhdr *)data)->h_proto;
+    if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */
+        DEBUG(3,"ray_cs translate_frame DIX II\n");
+        /* Copy LLC header to card buffer */
+        memcpy_toio((UCHAR *)&ptx->var, eth2_llc, sizeof(eth2_llc));
+        memcpy_toio( ((UCHAR *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2);
+        if ((proto == 0xf380) || (proto == 0x3781)) {
+            /* This is the selective translation table, only 2 entries */
+            writeb(0xf8, (UCHAR *) &((struct snaphdr_t *)ptx->var)->org[3]);
+        }
+        /* Copy body of ethernet packet without ethernet header */
+        memcpy_toio((UCHAR *)&ptx->var + sizeof(struct snaphdr_t), \
+                    data + ETH_HLEN,  len - ETH_HLEN);
+        return sizeof(struct snaphdr_t) - ETH_HLEN;
+    }
+    else { /* already  802 type, and proto is length */
+        DEBUG(3,"ray_cs translate_frame 802\n");
+        if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */
+        DEBUG(3,"ray_cs translate_frame evil IPX\n");
+            memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN,  len - ETH_HLEN);
+            return 0 - ETH_HLEN;
+        }
+        memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN,  len - ETH_HLEN);
+        return 0 - ETH_HLEN;
+    }
+    /* TBD do other frame types */
+} /* end translate_frame */
+/*===========================================================================*/
+void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
+                unsigned char *data)
+{
+    writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
+/*** IEEE 802.11 Address field assignments *************
+                     addr_1       addr_2     addr_3
+     AP              destination  AP(BSSID)  source
+     Infra Terminal  AP           terminal   destination
+     Adhoc           destination  terminal   BSSID
+*******************************************************/
+    if (local->net_type == ADHOC) {   
+        writeb(0, &ptx->mac.frame_ctl_2);
+        memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, 2 * ADDRLEN);
+        memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
+    }
+    else /* infrastructure */
+    {
+        if (local->sparm.b4.a_acting_as_ap_status)
+        {
+            writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);;
+            memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, ADDRLEN);
+            memcpy_toio(ptx->mac.addr_2, local->bss_id, 6);
+            memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_source, ADDRLEN);
+        }
+        else /* Terminal */
+        {
+            writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2);
+            memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN);
+            memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, ADDRLEN);
+            memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_dest, ADDRLEN);
+        }
+    }
+} /* end encapsulate_frame */
+/*===========================================================================*/
+int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    int err = 0;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_dev_ioctl - device not present\n");
+        return -1;
+    }
+    DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd);
+    /* Validate the command */
+    switch (cmd)
+    {
+        default:
+            DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd);
+            err = -EOPNOTSUPP;
+    }
+    return err;
+} /* end ray_dev_ioctl */
+/*===========================================================================*/
+int ray_open(struct net_device *dev)
+{
+    dev_link_t *link;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    
+    DEBUG(1, "ray_open('%s')\n", dev->name);
+
+    for (link = dev_list; link; link = link->next)
+        if (link->priv == dev) break;
+    if (!DEV_OK(link))
+        return -ENODEV;
+
+    if (link->open == 0) local->num_multi = 0;
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    dev->interrupt = 0;
+    if (sniffer) dev->tbusy = 1;
+    else         dev->tbusy = 0;
+    dev->start = 1;
+
+    DEBUG(2,"ray_open ending\n");
+    return 0;
+} /* end ray_open */
+/*===========================================================================*/
+int ray_dev_close(struct net_device *dev)
+{
+    dev_link_t *link;
+
+    DEBUG(1, "ray_dev_close('%s')\n", dev->name);
+
+    for (link = dev_list; link; link = link->next)
+        if (link->priv == dev) break;
+    if (link == NULL)
+        return -ENODEV;
+
+    link->open--; dev->start = 0;
+    if (link->state & DEV_STALE_CONFIG) {
+        link->release.expires = jiffies + HZ/20;
+        link->state |= DEV_RELEASE_PENDING;
+        add_timer(&link->release);
+    }
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+} /* end ray_dev_close */
+/*===========================================================================*/
+void ray_reset(struct net_device *dev) {
+    DEBUG(1,"ray_reset entered\n");
+    return;
+}
+/*===========================================================================*/
+/* Cause a firmware interrupt if it is ready for one                         */
+/* Return nonzero if not ready                                               */
+int interrupt_ecf(ray_dev_t *local, int ccs)
+{
+    int i = 50;
+/*    UCHAR *p = (local->amem + CIS_OFFSET + ECF_INTR_OFFSET); */
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs interrupt_ecf - device not present\n");
+        return -1;
+    }
+    DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs);
+
+/*    while ( i && (*p & ECF_INTR_SET))  i--; */
+    while ( i && 
+            (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET))
+        i--;
+    if (i == 0) {
+        DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n");
+        return -1;
+    }
+
+    *(local->sram + SCB_BASE) = ccs;
+    writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
+    return 0;
+} /* interrupt_ecf */
+/*===========================================================================*/
+/* Get next free transmit CCS                                                */
+/* Return - index of current tx ccs                                          */
+int get_free_tx_ccs(ray_dev_t *local)
+{
+    int i;
+    struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE);
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs get_free_tx_ccs - device not present\n");
+        return -1;
+    }
+
+    for (i=0; i < NUMBER_OF_TX_CCS; i++) {
+        if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
+            writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
+            writeb(CCS_END_LIST, &(pccs+i)->link);
+            return i;
+        }
+    }
+    DEBUG(1,"ray_cs ERROR no free tx CCS for raylink card\n");
+    return -1;
+} /* get_free_tx_ccs */
+/*===========================================================================*/
+/* Get next free CCS                                                         */
+/* Return - index of current ccs                                             */
+int get_free_ccs(ray_dev_t *local)
+{
+    int i;
+    struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE);
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs get_free_ccs - device not present\n");
+        return -1;
+    }
+    for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
+        if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
+            writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
+            writeb(CCS_END_LIST, &(pccs+i)->link);
+            return i;
+        }
+    }
+    DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n");
+    return -1;
+} /* get_free_ccs */
+/*===========================================================================*/
+void authenticate_timeout(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+    del_timer(&local->timer);
+    DEBUG(0,"ray_cs Authentication with access point failed - timeout\n");
+    join_net((u_long)local);
+}
+/*===========================================================================*/
+int asc_to_int(char a)
+{
+    if (a < '0') return -1;
+    if (a <= '9') return (a - '0');
+    if (a < 'A') return -1;
+    if (a <= 'F') return (10 + a - 'A');
+    if (a < 'a') return -1;
+    if (a <= 'f') return (10 + a - 'a');
+    return -1;
+}
+/*===========================================================================*/
+int parse_addr(char *in_str, UCHAR *out)
+{
+    int len;
+    int i,j,k;
+    int status;
+    
+    if (in_str == NULL) return 0;
+    if ((len = strlen(in_str)) < 2) return 0;
+    memset(out, 0, ADDRLEN);
+
+    status = 1;
+    j = len - 1;
+    if (j > 12) j = 12;
+    i = 5;
+    
+    while (j > 0)
+    {
+        if ((k = asc_to_int(in_str[j--])) != -1) out[i] = k;
+        else return 0;
+
+        if (j == 0) break;
+        if ((k = asc_to_int(in_str[j--])) != -1) out[i] += k << 4;
+        else return 0;
+        if (!i--) break;
+    }
+    return status;
+}
+/*===========================================================================*/
+struct enet_statistics *ray_get_stats(struct net_device *dev)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    struct status *p = (struct status *)(local->sram + STATUS_BASE);
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_cs enet_statistics - device not present\n");
+        return &local->stats;
+    }
+    if (p->mrx_overflow_for_host)
+    {
+        local->stats.rx_over_errors += ntohs(p->mrx_overflow);
+        p->mrx_overflow = 0;
+        p->mrx_overflow_for_host = 0;
+    }
+    if (p->mrx_checksum_error_for_host)
+    {
+        local->stats.rx_crc_errors += ntohs(p->mrx_checksum_error);
+        p->mrx_checksum_error = 0;
+        p->mrx_checksum_error_for_host = 0;
+    }
+    if (p->rx_hec_error_for_host)
+    {
+        local->stats.rx_frame_errors += ntohs(p->rx_hec_error);
+        p->rx_hec_error = 0;
+        p->rx_hec_error_for_host = 0;
+    }
+    return &local->stats;
+}
+/*===========================================================================*/
+void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    int ccsindex;
+    int i;
+    struct ccs *pccs;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(0,"ray_update_parm - device not present\n");
+        return;
+    }
+
+    if ((ccsindex = get_free_ccs(local)) == -1)
+    {
+        DEBUG(0,"ray_update_parm - No free ccs\n");
+        return;
+    }
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_UPDATE_PARAMS, &pccs->cmd);
+    writeb(objid, &pccs->var.update_param.object_id);
+    writeb(1, &pccs->var.update_param.number_objects);
+    writeb(0, &pccs->var.update_param.failure_cause);
+    for (i=0; i<len; i++) {
+        writeb(value[i], local->sram + HOST_TO_ECF_BASE);
+    }
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(0,"ray_cs associate failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+    }
+}
+/*===========================================================================*/
+static void ray_update_multi_list(struct net_device *dev, int all)
+{
+    struct dev_mc_list *dmi, **dmip;
+    int ccsindex;
+    struct ccs *pccs;
+    int i = 0;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    UCHAR *p = local->sram + HOST_TO_ECF_BASE;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(1,"ray_update_multi_list - device not present\n");
+        return;
+    }
+    else 
+        DEBUG(1,"ray_update_multi_list(%p)\n",dev);
+    if ((ccsindex = get_free_ccs(local)) == -1)
+    {
+        DEBUG(1,"ray_update_multi - No free ccs\n");
+        return;
+    }
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd);
+
+    if (all) {
+        writeb(0xff, &pccs->var);
+        local->num_multi = 0xff;
+    }
+    else {
+        /* Copy the kernel's list of MC addresses to card */
+        for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
+            memcpy_toio(p, dmi->dmi_addr, ETH_ALEN);
+            DEBUG(1,"ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",dmi->dmi_addr[0],dmi->dmi_addr[1],dmi->dmi_addr[2],dmi->dmi_addr[3],dmi->dmi_addr[4],dmi->dmi_addr[5]);
+            p += ETH_ALEN;
+            i++;
+        }
+        if (i > 256/ADDRLEN) i = 256/ADDRLEN;
+        writeb((UCHAR)i, &pccs->var);
+        DEBUG(1,"ray_cs update_multi %d addresses in list\n", i);
+        /* Interrupt the firmware to process the command */
+        local->num_multi = i;
+    }
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray_cs update_multi failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+    }
+} /* end ray_update_multi_list */
+/*===========================================================================*/
+static void set_multicast_list(struct net_device *dev)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    UCHAR promisc;
+
+    DEBUG(1,"ray_cs set_multicast_list(%p)\n",dev);
+
+    if (dev->flags & IFF_PROMISC)
+    {
+        if (local->sparm.b5.a_promiscuous_mode == 0) {
+            DEBUG(1,"ray_cs set_multicast_list promisc on\n");
+            local->sparm.b5.a_promiscuous_mode = 1;
+            promisc = 1;
+            ray_update_parm(dev,  OBJID_promiscuous_mode, \
+                            &promisc, sizeof(promisc));
+        }
+    }
+    else {
+        if (local->sparm.b5.a_promiscuous_mode == 1) {
+            DEBUG(1,"ray_cs set_multicast_list promisc off\n");
+            local->sparm.b5.a_promiscuous_mode = 0;
+            promisc = 0;
+            ray_update_parm(dev,  OBJID_promiscuous_mode, \
+                            &promisc, sizeof(promisc));
+        }
+    }
+
+    if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1);
+    else
+    {
+        if (local->num_multi != dev->mc_count) ray_update_multi_list(dev, 0);
+    }
+} /* end set_multicast_list */
+/*=============================================================================
+ * All routines below here are run at interrupt time.
+=============================================================================*/
+void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+    struct net_device *dev = (struct net_device *)dev_id;
+    dev_link_t *link;
+    ray_dev_t *local;
+    struct ccs *pccs;
+    struct rcs *prcs;
+    UCHAR rcsindex;
+    UCHAR tmp;
+    UCHAR cmd;
+    UCHAR status;
+
+    if (dev == NULL) {
+        link = dev_list;
+        dev = (struct net_device *)link->priv;
+        DEBUG(4,"ray_cs interrupt dev  = %p, link = %p\n",dev,link);
+        if (dev->irq != irq)
+        {
+            DEBUG(0,"ray_cs interrupt irq %d for unknown device.\n", irq);
+            return;
+        }
+    }
+    DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
+
+    if (dev->interrupt) {
+        printk("ray_cs Reentering interrupt handler not allowed\n");
+        return;
+    }
+    dev->interrupt = 1;
+    local = (ray_dev_t *)dev->priv;
+    link = (dev_link_t *)local->finder;
+    if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) {
+        DEBUG(1,"ray_cs interrupt from device not present or suspended.\n");
+        return;
+    }
+    rcsindex = ((struct scb *)(local->sram))->rcs_index;
+
+    if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS))
+    {
+        DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex);
+        clear_interrupt(local);
+        dev->interrupt = 0;
+        return;
+    }
+    if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */
+    {
+        pccs = ((struct ccs *) (local->sram + CCS_BASE)) + rcsindex;
+        cmd = readb(&pccs->cmd);
+        status = readb(&pccs->buffer_status);
+        switch (cmd)
+        {
+        case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */
+            del_timer(&local->timer);
+            if (status == CCS_COMMAND_COMPLETE) {
+                DEBUG(1,"ray_cs interrupt download_startup_parameters OK\n");
+            }
+            else {
+                DEBUG(1,"ray_cs interrupt download_startup_parameters fail\n");
+            }
+            break;
+        case CCS_UPDATE_PARAMS:
+            DEBUG(1,"ray_cs interrupt update params done\n");
+            if (status != CCS_COMMAND_COMPLETE) {
+                tmp = readb(&pccs->var.update_param.failure_cause);
+            DEBUG(0,"ray_cs interrupt update params failed - reason %d\n",tmp);
+            }
+            break;
+        case CCS_REPORT_PARAMS:
+            DEBUG(1,"ray_cs interrupt report params done\n");
+            break;
+        case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */
+            DEBUG(1,"ray_cs interrupt CCS Update Multicast List done\n");
+            break;
+        case CCS_UPDATE_POWER_SAVINGS_MODE:
+            DEBUG(1,"ray_cs interrupt update power save mode done\n");
+            break;
+        case CCS_START_NETWORK:
+        case CCS_JOIN_NETWORK:
+            if (status == CCS_COMMAND_COMPLETE) {
+                if (readb(&pccs->var.start_network.net_initiated) == 1) {
+                    DEBUG(0,"ray_cs interrupt network \"%s\"started\n",\
+                          local->sparm.b4.a_current_ess_id);
+                }
+                else {
+                    DEBUG(0,"ray_cs interrupt network \"%s\" joined\n",\
+                          local->sparm.b4.a_current_ess_id);
+                }
+                memcpy_fromio(&local->bss_id,pccs->var.start_network.bssid,ADDRLEN);
+
+                if (local->fw_ver == 0x55) local->net_default_tx_rate = 3;
+                else local->net_default_tx_rate = 
+                         readb(&pccs->var.start_network.net_default_tx_rate);
+                local->encryption = readb(&pccs->var.start_network.encryption);
+                if (!sniffer && (local->net_type == INFRA)
+                    && !(local->sparm.b4.a_acting_as_ap_status)) {
+                    authenticate(local);
+                }
+                local->card_status = CARD_ACQ_COMPLETE;
+            }
+            else {
+                local->card_status = CARD_ACQ_FAILED;
+
+                del_timer(&local->timer);
+                local->timer.expires = jiffies + HZ*5;
+                local->timer.data = (long)local;
+                if (status == CCS_START_NETWORK) {
+                    DEBUG(0,"ray_cs interrupt network \"%s\" start failed\n",\
+                          local->sparm.b4.a_current_ess_id);
+                    local->timer.function = &start_net;
+                }
+                else {
+                    DEBUG(0,"ray_cs interrupt network \"%s\" join failed\n",\
+                          local->sparm.b4.a_current_ess_id);
+                    local->timer.function = &join_net;
+                }
+                add_timer(&local->timer);
+            }
+            break;
+        case CCS_START_ASSOCIATION:
+            if (status == CCS_COMMAND_COMPLETE) {
+                local->card_status = CARD_ASSOC_COMPLETE;
+                DEBUG(0,"ray_cs association successful\n");
+            }
+            else
+            {
+                DEBUG(0,"ray_cs association failed,\n");
+                local->card_status = CARD_ASSOC_FAILED;
+                join_net((u_long)local);
+            }
+            break;
+        case CCS_TX_REQUEST:
+            if (status == CCS_COMMAND_COMPLETE) {
+                DEBUG(3,"ray_cs interrupt tx request complete\n");
+            }
+            else {
+                DEBUG(1,"ray_cs interrupt tx request failed\n");
+            }
+            if (!sniffer) dev->tbusy = 0;
+            mark_bh(NET_BH);
+            break;
+        case CCS_TEST_MEMORY:
+            DEBUG(1,"ray_cs interrupt mem test done\n");
+            break;
+        case CCS_SHUTDOWN:
+            DEBUG(1,"ray_cs interrupt Unexpected CCS returned - Shutdown\n");
+            break;
+        case CCS_DUMP_MEMORY:
+            DEBUG(1,"ray_cs interrupt dump memory done\n");
+            break;
+        case CCS_START_TIMER:
+            DEBUG(2,"ray_cs interrupt DING - raylink timer expired\n");
+            break;
+        default:
+            DEBUG(1,"ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",\
+                  rcsindex, cmd);
+        }
+        writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
+    }
+    else /* It's an RCS */
+    {
+        prcs = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex;
+    
+        switch (readb(&prcs->interrupt_id))
+        {
+        case PROCESS_RX_PACKET:
+            ray_rx(dev, local, prcs);
+            break;
+        case REJOIN_NET_COMPLETE:
+            DEBUG(1,"ray_cs interrupt rejoin net complete\n");
+            local->card_status = CARD_ACQ_COMPLETE;
+            /* do we need to clear tx buffers CCS's? */
+            if (local->sparm.b4.a_network_type == ADHOC) {
+                if (!sniffer) dev->tbusy = 0;
+            }
+            else {
+                memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete.bssid, ADDRLEN);
+                DEBUG(1,"ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",\
+                      local->bss_id[0], local->bss_id[1], local->bss_id[2],\
+                      local->bss_id[3], local->bss_id[4], local->bss_id[5]);
+                if (!sniffer) authenticate(local);
+            }
+            break;
+        case ROAMING_INITIATED:
+            DEBUG(1,"ray_cs interrupt roaming initiated\n"); 
+            dev->tbusy = 1;
+            local->card_status = CARD_DOING_ACQ;
+            break;
+        case JAPAN_CALL_SIGN_RXD:
+            DEBUG(1,"ray_cs interrupt japan call sign rx\n");
+            break;
+        default:
+            DEBUG(1,"ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",\
+                  rcsindex, readb(&prcs->interrupt_id));
+            break;
+        }
+        writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
+    }
+    clear_interrupt(local);
+    dev->interrupt = 0;
+} /* ray_interrupt */
+/*===========================================================================*/
+void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs)
+{
+    int rx_len;
+    unsigned int pkt_addr;
+    UCHAR *pmsg;
+    DEBUG(4,"ray_rx process rx packet\n");
+
+    /* Calculate address of packet within Rx buffer */
+    pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8)
+                + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END;
+    /* Length of first packet fragment */
+    rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
+        + readb(&prcs->var.rx_packet.rx_data_length[1]);
+
+    pmsg = local->rmem + pkt_addr;
+    switch(readb(pmsg))
+    {
+    case DATA_TYPE:
+	    DEBUG(4,"ray_rx data type\n");
+        rx_data(dev, prcs, pkt_addr, rx_len);
+        break;
+    case AUTHENTIC_TYPE:
+	    DEBUG(4,"ray_rx authentic type\n");
+        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
+        else rx_authenticate(local, prcs, pkt_addr, rx_len);
+        break;
+    case DEAUTHENTIC_TYPE:
+	    DEBUG(4,"ray_rx deauth type\n");
+        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
+        else rx_deauthenticate(local, prcs, pkt_addr, rx_len);
+        break;
+    case NULL_MSG_TYPE:
+        DEBUG(3,"ray_cs rx NULL msg\n");
+        break;
+    case BEACON_TYPE:
+	    DEBUG(4,"ray_rx beacon type\n");
+        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
+
+        copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, 
+                          rx_len < sizeof(struct beacon_rx) ? 
+                          rx_len : sizeof(struct beacon_rx));
+
+        /* Get the statistics so the card counters never overflow */
+        ray_get_stats(dev);
+            break;
+    default:
+        DEBUG(0,"ray_cs unknown pkt type %2x\n", readb(pmsg));
+        break;
+    }
+
+} /* end ray_rx */
+/*===========================================================================*/
+void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
+             int rx_len)
+{
+    struct sk_buff *skb = NULL;
+    struct rcs *prcslink = prcs;
+    ray_dev_t *local = dev->priv;
+    UCHAR *rx_ptr;
+    int total_len;
+    int tmp;
+
+    if (!sniffer) {
+        if (translate) {
+/* TBD length needs fixing for translated header */
+            if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
+                rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) 
+            {
+                DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len);
+                return;
+            }
+        }
+        else /* encapsulated ethernet */ {
+            if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
+                rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN))
+            {
+                DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len);
+                return;
+            }
+        }
+    }
+    DEBUG(4,"ray_cs rx_data packet\n");
+    /* If fragmented packet, verify sizes of fragments add up */
+    if (prcs->var.rx_packet.next_frag_rcs_index != 0xFF) {
+        DEBUG(1,"ray_cs rx'ed fragment\n");
+        tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
+            +  readb(&prcs->var.rx_packet.totalpacketlength[1]);
+        total_len = tmp;
+        prcslink = prcs;
+        do {
+            tmp -= (readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8)
+                +   readb(&prcslink->var.rx_packet.rx_data_length[1]);
+            if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF
+                || tmp < 0) break;
+            prcslink = ((struct rcs *)(local->sram + CCS_BASE))
+                + readb(&prcslink->link_field);
+        } while (1);
+
+        if (tmp < 0)
+        {
+            DEBUG(0,"ray_cs rx_data fragment lengths don't add up\n");
+            local->stats.rx_dropped++; 
+            release_frag_chain(local, prcs);
+            return;
+        }
+    }
+    else { /* Single unfragmented packet */
+        total_len = rx_len;
+    }
+
+    skb = dev_alloc_skb( total_len+5 );
+    if (skb == NULL)
+    {
+        DEBUG(0,"ray_cs rx_data could not allocate skb\n");
+        local->stats.rx_dropped++; 
+        if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF)
+            release_frag_chain(local, prcs);
+        return;
+    }
+    skb_reserve( skb, 2);   /* Align IP on 16 byte (TBD check this)*/
+    skb->dev = dev;
+
+    DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len);
+
+/************************/
+    /* Reserve enough room for the whole damn packet. */
+    rx_ptr = skb_put( skb, total_len);
+    /* Copy the whole packet to sk_buff */
+    rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
+
+    /* Now, deal with encapsulation/translation/sniffer */
+    if (!sniffer) {
+        if (!translate) { 
+            /* Encapsulated ethernet, so just lop off 802.11 MAC header */
+/* TBD reserve            skb_reserve( skb, RX_MAC_HEADER_LENGTH); */
+            skb_pull( skb, RX_MAC_HEADER_LENGTH);
+        }
+        else {
+            /* Do translation */
+            untranslate(local, skb, total_len);
+        }
+    }
+    else 
+    {  /* sniffer mode, so just pass whole packet */  };
+
+/************************/
+    /* Now pick up the rest of the fragments if any */
+    tmp = 17; 
+    if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
+        prcslink = prcs;
+        DEBUG(1,"ray_cs rx_data in fragment loop\n");
+        do {
+            prcslink = ((struct rcs *)(local->sram + CCS_BASE))
+                + readb(&prcslink->var.rx_packet.next_frag_rcs_index);
+            rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8)
+                      + readb(&prcslink->var.rx_packet.rx_data_length[1]))
+                & RX_BUFF_END;
+            pkt_addr = (( readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << 8)
+                        + readb(&prcslink->var.rx_packet.rx_data_ptr[1]))
+                & RX_BUFF_END;
+
+            rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len);
+
+        } while (tmp-- && 
+                 readb(&prcslink->var.rx_packet.next_frag_rcs_index) != 0xFF);
+        release_frag_chain(local, prcs);
+    }
+
+    skb->protocol = eth_type_trans(skb,dev);
+    netif_rx(skb);
+
+    local->stats.rx_packets++;
+    local->stats.rx_bytes += skb->len;
+} /* end rx_data */
+/*===========================================================================*/
+void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
+{
+    snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH);
+    struct mac_header *pmac = (struct mac_header *)skb->data;
+    unsigned short type = *(unsigned short *)psnap->ethertype;
+    unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff;
+    unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff;
+    int delta;
+    struct ethhdr *peth;
+    UCHAR srcaddr[ADDRLEN];
+    UCHAR destaddr[ADDRLEN];
+    int i;
+
+    if (local->sparm.b5.a_acting_as_ap_status != TYPE_STA)  
+        memcpy(destaddr, pmac->addr_3, ADDRLEN);
+    else
+        memcpy(destaddr, pmac->addr_1, ADDRLEN);
+    memcpy(srcaddr, pmac->addr_2, ADDRLEN);
+
+    DEBUG(3,"skb->data before untranslate");
+    for (i=0;i<64;i++) 
+        DEBUG(3,"%02x ",skb->data[i]);
+    DEBUG(3,"\ntype = %08x, xsap = %08x, org = %08x\n",type,xsap,org);
+    DEBUG(3,"untranslate skb->data = %p\n",skb->data);
+
+    if ( xsap != SNAP_ID) {
+        /* not a snap type so leave it alone */
+        DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff);
+
+        delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+        peth = (struct ethhdr *)(skb->data + delta);
+        peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
+    }
+    else { /* Its a SNAP */
+        if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC  */
+        DEBUG(3,"ray_cs untranslate Bridge encap\n");
+            delta = RX_MAC_HEADER_LENGTH 
+                + sizeof(struct snaphdr_t) - ETH_HLEN;
+            peth = (struct ethhdr *)(skb->data + delta);
+            peth->h_proto = type;
+        }
+        else {
+            if (org == RFC1042_ENCAP) {
+                switch (type) {
+                case RAY_IPX_TYPE:
+                case APPLEARP_TYPE:
+                    DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n");
+                    delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+                    peth = (struct ethhdr *)(skb->data + delta);
+                    peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
+                    break;
+                default:
+                    DEBUG(3,"ray_cs untranslate RFC default\n");
+                    delta = RX_MAC_HEADER_LENGTH + 
+                        sizeof(struct snaphdr_t) - ETH_HLEN;
+                    peth = (struct ethhdr *)(skb->data + delta);
+                    peth->h_proto = type;
+                    break;
+                }
+            }
+            else {
+                printk("ray_cs untranslate very confused by packet\n");
+                delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+                peth = (struct ethhdr *)(skb->data + delta);
+                peth->h_proto = type;
+            }
+        }
+    }
+/* TBD reserve  skb_reserve(skb, delta); */
+    skb_pull(skb, delta);
+    DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data);
+    memcpy(peth->h_dest, destaddr, ADDRLEN);
+    memcpy(peth->h_source, srcaddr, ADDRLEN);
+    DEBUG(3,"skb->data after untranslate:");
+    for (i=0;i<64;i++) 
+        DEBUG(3,"%02x ",skb->data[i]);
+    DEBUG(3,"\n");
+} /* end untranslate */
+/*===========================================================================*/
+/* Copy data from circular receive buffer to PC memory.
+ * dest     = destination address in PC memory
+ * pkt_addr = source address in receive buffer
+ * len      = length of packet to copy
+ */
+int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length)
+{
+    int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
+    if (wrap_bytes <= 0)
+    {
+        memcpy_fromio(dest,local->rmem + pkt_addr,length);
+    }
+    else /* Packet wrapped in circular buffer */
+    {
+        memcpy_fromio(dest,local->rmem+pkt_addr,length - wrap_bytes);
+        memcpy_fromio(dest + length - wrap_bytes, local->rmem, wrap_bytes);
+    }
+    return length;
+}
+/*===========================================================================*/
+void release_frag_chain(ray_dev_t *local, struct rcs* prcs)
+{
+    struct rcs *prcslink = prcs;
+    int tmp = 17;
+    unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index);
+
+    while (tmp--) {
+        writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
+        if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
+            DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex);
+            break;      
+        }   
+        prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex;
+        rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index);
+    }
+    writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
+}
+/*===========================================================================*/
+void authenticate(ray_dev_t *local)
+{
+    dev_link_t *link = local->finder;
+    DEBUG(0,"ray_cs Starting authentication.\n");
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(1,"ray_cs authenticate - device not present\n");
+        return;
+    }
+
+    del_timer(&local->timer);
+    if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
+        local->timer.function = &join_net;
+    }
+    else {
+        local->timer.function = &authenticate_timeout;
+    }
+    local->timer.expires = jiffies + HZ*2;
+    local->timer.data = (long)local;
+    add_timer(&local->timer);
+    local->authentication_state = AWAITING_RESPONSE;
+} /* end authenticate */
+/*===========================================================================*/
+void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
+                     unsigned int pkt_addr, int rx_len)
+{
+    UCHAR buff[256];
+    struct rx_msg *msg = (struct rx_msg *)buff;
+    
+    del_timer(&local->timer);
+
+    copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
+	/* if we are trying to get authenticated */
+    if (local->sparm.b4.a_network_type == ADHOC) {
+		DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]);
+		if (msg->var[2] == 1) {
+                    DEBUG(0,"ray_cs Sending authentication response.\n");
+                    if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
+                        local->authentication_state = NEED_TO_AUTH;
+                        memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN);
+                    }
+		}
+	}
+	else /* Infrastructure network */
+	{
+		if (local->authentication_state == AWAITING_RESPONSE) {
+			/* Verify authentication sequence #2 and success */
+			if (msg->var[2] == 2) {
+				if ((msg->var[3] | msg->var[4]) == 0) {
+					DEBUG(1,"Authentication successful\n");
+					local->card_status = CARD_AUTH_COMPLETE;
+					associate(local);
+					local->authentication_state = AUTHENTICATED;
+				}
+				else {
+					DEBUG(0,"Authentication refused\n");
+					local->card_status = CARD_AUTH_REFUSED;
+					join_net((u_long)local);
+					local->authentication_state = UNAUTHENTICATED;
+				}
+			}
+		}
+	}
+
+} /* end rx_authenticate */
+/*===========================================================================*/
+void associate(ray_dev_t *local)
+{
+    struct ccs *pccs;
+    dev_link_t *link = local->finder;
+    struct net_device *dev = link->priv;
+    int ccsindex;
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(1,"ray_cs associate - device not present\n");
+        return;
+    }
+    /* If no tx buffers available, return*/
+    if ((ccsindex = get_free_ccs(local)) == -1)
+    {
+/* TBD should never be here but... what if we are? */
+        DEBUG(1,"ray_cs associate - No free ccs\n");
+        return;
+    }
+    DEBUG(1,"ray_cs Starting association with access point\n");
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    /* fill in the CCS */
+    writeb(CCS_START_ASSOCIATION, &pccs->cmd);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray_cs associate failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+
+        del_timer(&local->timer);
+        local->timer.expires = jiffies + HZ*2;
+        local->timer.data = (long)local;
+        local->timer.function = &join_net;
+        add_timer(&local->timer);
+        local->card_status = CARD_ASSOC_FAILED;
+        return;
+    }
+    if (!sniffer) dev->tbusy = 0;
+
+} /* end associate */
+/*===========================================================================*/
+void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
+                       unsigned int pkt_addr, int rx_len)
+{
+/*  UCHAR buff[256];
+    struct rx_msg *msg = (struct rx_msg *)buff;
+*/
+    DEBUG(0,"Deauthentication frame received\n");
+	local->authentication_state = UNAUTHENTICATED;
+    /* Need to reauthenticate or rejoin depending on reason code */
+/*  copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
+ */
+}
+/*===========================================================================*/
+void clear_interrupt(ray_dev_t *local)
+{
+    writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
+}
+/*===========================================================================*/
+#ifdef CONFIG_PROC_FS
+#define MAXDATA (PAGE_SIZE - 80)
+
+static char *card_status[] = {
+    "Card inserted - uninitialized",     /* 0 */
+    "Card not downloaded",               /* 1 */
+    "Waiting for download parameters",   /* 2 */
+    "Card doing acquisition",            /* 3 */
+    "Acquisition complete",              /* 4 */
+    "Authentication complete",           /* 5 */
+    "Association complete",              /* 6 */
+    "???", "???", "???", "???",          /* 7 8 9 10 undefined */
+    "Card init error",                   /* 11 */
+    "Download parameters error",         /* 12 */
+    "???",                               /* 13 */
+    "Acquisition failed",                /* 14 */
+    "Authentication refused",            /* 15 */
+    "Association failed"                 /* 16 */
+};
+
+static char *nettype[] = {"Adhoc", "Infra "};
+static char *framing[] = {"Encapsulation", "Translation"}
+;
+/*===========================================================================*/
+int ray_cs_proc_read(char *buf, char **start, off_t offset, 
+                     int len, int unused)
+{
+/* Print current values which are not available via other means
+ * eg ifconfig 
+ */
+    int i;
+    dev_link_t *link = dev_list;
+    struct net_device *dev = (struct net_device *)link->priv;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    UCHAR *p;
+    struct freq_hop_element *pfh;
+    UCHAR c[33];
+
+    len = 0;
+
+    len += sprintf(buf + len, "Raylink Wireless LAN driver status\n");
+    len += sprintf(buf + len, "%s\n", rcsid);
+    /* build 4 does not report version, and field is 0x55 after memtest */
+    len += sprintf(buf + len, "Firmware version     = ");
+    if (local->fw_ver == 0x55)
+        len += sprintf(buf + len, "4 - Use dump_cis for more details\n");
+    else
+        len += sprintf(buf + len, "%2d.%02d.%02d\n",
+                   local->fw_ver, local->fw_bld, local->fw_var);
+
+    for (i=0; i<32; i++) c[i] = local->sparm.b5.a_current_ess_id[i];
+    c[32] = 0;
+    len += sprintf(buf + len, "%s network ESSID = \"%s\"\n", 
+                   nettype[local->sparm.b5.a_network_type], c);
+
+    p = local->bss_id;
+    len += sprintf(buf + len, 
+                   "BSSID                = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                   p[0],p[1],p[2],p[3],p[4],p[5]);
+
+    len += sprintf(buf + len, "Country code         = %d\n", 
+                   local->sparm.b5.a_curr_country_code);
+
+    i = local->card_status;
+    if (i < 0) i = 10;
+    if (i > 16) i = 10;
+    len += sprintf(buf + len, "Card status          = %s\n", card_status[i]);
+
+    len += sprintf(buf + len, "Framing mode         = %s\n",framing[translate]);
+
+    /* Pull some fields out of last beacon received */
+    len += sprintf(buf + len, "Beacon Interval      = %d Kus\n", 
+                   local->last_bcn.beacon_intvl[0]
+                   + 256 * local->last_bcn.beacon_intvl[1]);
+    
+    p = local->last_bcn.elements;
+    if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2;
+    else {
+        len += sprintf(buf + len, "Parse beacon failed at essid element id = %d\n",p[0]);
+        return len;
+    }
+
+    if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
+        len += sprintf(buf + len, "Supported rate codes = ");
+        for (i=2; i<p[1] + 2; i++) 
+            len += sprintf(buf + len, "0x%02x ", p[i]);
+        len += sprintf(buf + len, "\n");
+        p += p[1] + 2;
+    }
+    else {
+        len += sprintf(buf + len, "Parse beacon failed at rates element\n");
+        return len;
+    }
+
+    if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
+        pfh = (struct freq_hop_element *)p;
+        len += sprintf(buf + len, "Hop dwell            = %d Kus\n",
+                       pfh->dwell_time[0] + 256 * pfh->dwell_time[1]);
+        len += sprintf(buf + len, "Hop set              = %d \n", pfh->hop_set);
+        len += sprintf(buf + len, "Hop pattern          = %d \n", pfh->hop_pattern);
+        len += sprintf(buf + len, "Hop index            = %d \n", pfh->hop_index);
+        p += p[1] + 2;
+    }
+    else {
+        len += sprintf(buf + len, "Parse beacon failed at FH param element\n");
+        return len;
+    }
+    return len;
+}
+
+#endif
+/*===========================================================================*/
+int  build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
+{
+    int addr;
+    struct ccs *pccs;
+    struct tx_msg *ptx;
+    int ccsindex;
+
+    /* If no tx buffers available, return */
+    if ((ccsindex = get_free_tx_ccs(local)) == -1)
+    {
+/* TBD should never be here but... what if we are? */
+        DEBUG(1,"ray_cs send authenticate - No free tx ccs\n");
+        return -1;
+    }
+
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+
+    /* Address in card space */
+    addr = TX_BUF_BASE + (ccsindex << 11);
+    /* fill in the CCS */
+    writeb(CCS_TX_REQUEST, &pccs->cmd);
+    writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr);
+    writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1);
+    writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length);
+    writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1);
+    writeb(0, &pccs->var.tx_request.pow_sav_mode);
+
+    ptx = (struct tx_msg *)(local->sram + addr);
+    /* fill in the mac header */
+    writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1);
+    writeb(0, &ptx->mac.frame_ctl_2);
+
+    memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN);
+    memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN);
+    memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
+
+    /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */
+    memset_io(ptx->var, 0, 6);
+    writeb(auth_type & 0xff, ptx->var + 2);
+
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray_cs send authentication request failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return -1;
+    }
+    return 0;
+} /* End build_auth_frame */
+/*===========================================================================*/
+int init_ray_cs(void)
+{
+    int rc;
+    servinfo_t serv;
+    
+    DEBUG(1, "%s\n", rcsid);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+        printk(KERN_NOTICE "ray: Card Services release does not match!\n");
+        return -1;
+    }
+    rc = register_pcmcia_driver(&dev_info, &ray_attach, &ray_detach);
+    DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc);
+    proc_register(&proc_root, &ray_cs_proc_entry);
+    if (translate != 0) translate = 1;
+    return 0;
+} /* init_module */
+
+static char init_ess_id[ESSID_SIZE];
+
+static int __init essid_setup(char *str)
+{
+	strncpy(init_ess_id, str, ESSID_SIZE);
+	essid = init_ess_id;
+	return 1;
+}
+
+__setup("essid=", essid_setup);
+
+/*===========================================================================*/
+#ifdef MODULE
+int init_module(void)
+{
+	init_ray_cs();
+}
+
+void cleanup_module(void)
+{
+    DEBUG(0, "ray_cs: cleanup_module\n");
+
+    unregister_pcmcia_driver(&dev_info);
+    while (dev_list != NULL) {
+        if (dev_list->state & DEV_CONFIG) ray_release((u_long)dev_list);
+        ray_detach(dev_list);
+    }
+    proc_unregister(&proc_root, ray_cs_proc_entry.low_ino);
+} /* cleanup_module */
+#endif
+/*===========================================================================*/
diff -u --recursive --new-file v2.3.17/linux/drivers/net/pcmcia/ray_cs.h linux/drivers/net/pcmcia/ray_cs.h
--- v2.3.17/linux/drivers/net/pcmcia/ray_cs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/ray_cs.h	Thu Sep  9 13:02:45 1999
@@ -0,0 +1,60 @@
+/* Raytheon wireless LAN PCMCIA card driver for Linux 
+   A  PCMCIA client driver for the Raylink wireless network card
+   Written by Corey Thomas
+*/
+
+#ifndef RAYLINK_H
+
+struct beacon_rx {
+    struct mac_header mac;
+    UCHAR timestamp[8];
+    UCHAR beacon_intvl[2];
+    UCHAR capability[2];
+    UCHAR elements[sizeof(struct essid_element) 
+                  + sizeof(struct rates_element)
+                  + sizeof(struct freq_hop_element) 
+                  + sizeof(struct japan_call_sign_element)
+                  + sizeof(struct tim_element)];
+};
+
+typedef struct ray_dev_t {
+    int card_status;
+	int authentication_state;
+    dev_node_t  node;
+    window_handle_t amem_handle;   /* handle to window for attribute memory  */
+    window_handle_t rmem_handle;   /* handle to window for rx buffer on card */
+    UCHAR *sram;                   /* pointer to beginning of shared RAM     */
+    UCHAR *amem;                   /* pointer to attribute mem window        */
+    UCHAR *rmem;                   /* pointer to receive buffer window       */
+    dev_link_t *finder;            /* pointer back to dev_link_t for card    */
+    struct timer_list timer;
+    int   dl_param_ccs;
+    union {
+        struct b4_startup_params b4;
+        struct b5_startup_params b5;
+    } sparm;
+    int timeout_flag;
+    UCHAR supported_rates[8];
+    UCHAR japan_call_sign[12];
+    struct startup_res_6 startup_res;
+    int num_multi;
+    /* Network parameters from start/join */
+    UCHAR bss_id[6];
+    UCHAR auth_id[6];
+    UCHAR net_default_tx_rate;
+    UCHAR encryption;
+    struct enet_statistics stats;
+
+    UCHAR net_type;
+    UCHAR sta_type;
+    UCHAR fw_ver;
+    UCHAR fw_bld;
+    UCHAR fw_var;
+    UCHAR ASIC_version;
+    UCHAR assoc_id[2];
+    UCHAR tib_length;
+    struct beacon_rx last_bcn;
+} ray_dev_t;
+/*****************************************************************************/
+
+#endif /* RAYLINK_H */
diff -u --recursive --new-file v2.3.17/linux/drivers/net/pcmcia/rayctl.h linux/drivers/net/pcmcia/rayctl.h
--- v2.3.17/linux/drivers/net/pcmcia/rayctl.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/pcmcia/rayctl.h	Thu Sep  9 13:02:45 1999
@@ -0,0 +1,725 @@
+#ifndef RAYLINK_H
+
+typedef unsigned char UCHAR;
+
+/****** IEEE 802.11 constants ************************************************/
+#define ADDRLEN           6
+/* Frame control 1 bit fields */
+#define PROTOCOL_VER      0x00
+#define DATA_TYPE         0x08
+#define ASSOC_REQ_TYPE    0x00
+#define ASSOC_RESP_TYPE   0x10
+#define REASSOC_REQ_TYPE  0x20
+#define REASSOC_RESP_TYPE 0x30
+#define NULL_MSG_TYPE     0x48
+#define BEACON_TYPE       0x80
+#define DISASSOC_TYPE     0xA0
+#define PSPOLL_TYPE       0xA4
+#define AUTHENTIC_TYPE    0xB0
+#define DEAUTHENTIC_TYPE  0xC0
+/* Frame control 2 bit fields */
+#define FC2_TO_DS         0x01
+#define FC2_FROM_DS       0x02
+#define FC2_MORE_FRAG     0x04
+#define FC2_RETRY         0x08
+#define FC2_PSM           0x10
+#define FC2_MORE_DATA     0x20
+#define FC2_WEP           0x40
+#define FC2_ORDER         0x80
+/*****************************************************************************/
+/* 802.11 element ID's and lengths */
+#define C_BP_CAPABILITY_ESS             0x01
+#define C_BP_CAPABILITY_IBSS            0x02
+#define C_BP_CAPABILITY_CF_POLLABLE     0x04
+#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08
+#define C_BP_CAPABILITY_PRIVACY         0x10
+
+#define C_ESSID_ELEMENT_ID               0
+#define C_ESSID_ELEMENT_MAX_LENGTH       32
+
+#define C_SUPPORTED_RATES_ELEMENT_ID     1
+#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2
+
+#define C_FH_PARAM_SET_ELEMENT_ID        2
+#define C_FH_PARAM_SET_ELEMENT_LNGTH     5
+
+#define C_CF_PARAM_SET_ELEMENT_ID        4
+#define C_CF_PARAM_SET_ELEMENT_LNGTH     6
+
+#define C_TIM_ELEMENT_ID                 5
+#define C_TIM_BITMAP_LENGTH            251
+#define C_TIM_BMCAST_BIT              0x01
+
+#define C_IBSS_ELEMENT_ID                6
+#define C_IBSS_ELEMENT_LENGTH            2
+
+#define C_JAPAN_CALL_SIGN_ELEMENT_ID    51
+#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12
+
+#define C_DISASSOC_REASON_CODE_LEN       2
+#define C_DISASSOC_REASON_CODE_DEFAULT   8
+
+#define C_CRC_LEN                        4
+#define C_NUM_SUPPORTED_RATES            8 
+/****** IEEE 802.11 mac header for type data packets *************************/
+struct mac_header {
+  UCHAR frame_ctl_1;                          
+  UCHAR frame_ctl_2;
+  UCHAR duration_lsb;
+  UCHAR duration_msb;
+  UCHAR addr_1[ADDRLEN];
+  UCHAR addr_2[ADDRLEN];
+  UCHAR addr_3[ADDRLEN];
+  UCHAR seq_frag_num[2];
+/*  UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */
+};
+/****** IEEE 802.11 frame element structures *********************************/
+struct essid_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH];
+};
+struct rates_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR value[8];
+};
+struct freq_hop_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR dwell_time[2];
+  UCHAR hop_set;
+  UCHAR hop_pattern;
+  UCHAR hop_index;
+};
+struct tim_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR dtim_count;
+  UCHAR dtim_period;    
+  UCHAR bitmap_control;
+  UCHAR tim[C_TIM_BITMAP_LENGTH];
+};
+struct ibss_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR atim_window[2];
+};
+struct japan_call_sign_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR call_sign[12];
+};
+/****** Beacon message structures ********************************************/
+/* .elements is a large lump of max size because elements are variable size  */
+struct infra_beacon
+{
+    UCHAR timestamp[8];
+    UCHAR beacon_intvl[2];
+    UCHAR capability[2];
+    UCHAR elements[sizeof(struct essid_element) 
+                  + sizeof(struct rates_element)
+                  + sizeof(struct freq_hop_element) 
+                  + sizeof(struct japan_call_sign_element)
+                  + sizeof(struct tim_element)];
+};
+struct adhoc_beacon
+{
+    UCHAR timestamp[8];
+    UCHAR beacon_intvl[2];
+    UCHAR capability[2];
+    UCHAR elements[sizeof(struct essid_element) 
+                  + sizeof(struct rates_element)
+                  + sizeof(struct freq_hop_element) 
+                  + sizeof(struct japan_call_sign_element)
+                  + sizeof(struct ibss_element)];
+};
+/*****************************************************************************/
+/*****************************************************************************/
+
+
+/* #define C_MAC_HDR_2_WEP 0x40 */
+/* TX/RX CCS constants */
+#define TX_HEADER_LENGTH 0x1C
+#define RX_MAC_HEADER_LENGTH 0x18
+#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6)
+#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
+#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
+#define FCS_LEN           4
+
+#define ADHOC                 0
+#define INFRA                 1
+
+#define TYPE_STA              0
+#define TYPE_AP               1
+
+#define PASSIVE_SCAN          1
+#define ACTIVE_SCAN           1
+
+#define PSM_CAM               0
+
+/* Country codes */
+#define USA                   1
+#define EUROPE                2
+#define JAPAN                 3
+#define KOREA                 4
+#define SPAIN                 5
+#define FRANCE                6
+#define ISRAEL                7
+#define AUSTRALIA             8
+#define JAPAN_TEST            9
+
+/* Hop pattern lengths */
+#define USA_HOP_MOD          79 
+#define EUROPE_HOP_MOD       79 
+#define JAPAN_HOP_MOD        23
+#define KOREA_HOP_MOD        23
+#define SPAIN_HOP_MOD        27
+#define FRANCE_HOP_MOD       35
+#define ISRAEL_HOP_MOD       35
+#define AUSTRALIA_HOP_MOD    47
+#define JAPAN_TEST_HOP_MOD   23
+
+#define ESSID_SIZE           32
+/**********************************************************************/
+/* CIS Register Constants */
+#define CIS_OFFSET             0x0f00
+/* Configuration Option Register (0x0F00) */
+#define COR_OFFSET             0x00
+#define COR_SOFT_RESET         0x80
+#define COR_LEVEL_IRQ          0x40
+#define COR_CONFIG_NUM         0x01
+#define COR_DEFAULT            (COR_LEVEL_IRQ | COR_CONFIG_NUM)
+
+/* Card Configuration and Status Register (0x0F01) */
+#define CCSR_OFFSET            0x01
+#define CCSR_HOST_INTR_PENDING 0x01
+#define CCSR_POWER_DOWN        0x04
+
+/* HCS Interrupt Register (0x0F05) */
+#define HCS_INTR_OFFSET        0x05
+/* #define HCS_INTR_OFFSET        0x0A */
+#define HCS_INTR_CLEAR         0x00
+
+/* ECF Interrupt Register (0x0F06) */
+#define ECF_INTR_OFFSET        0x06
+/* #define ECF_INTR_OFFSET        0x0C */
+#define ECF_INTR_SET           0x01
+
+/* Authorization Register 0 (0x0F08) */
+#define AUTH_0_ON              0x57
+
+/* Authorization Register 1 (0x0F09) */
+#define AUTH_1_ON              0x82
+
+/* Program Mode Register (0x0F0A) */
+#define PC2PM                  0x02
+#define PC2CAL                 0x10
+#define PC2MLSE                0x20
+
+/* PC Test Mode Register (0x0F0B) */
+#define PC_TEST_MODE           0x08
+
+/* Frequency Control Word (0x0F10) */
+/* Range 0x02 - 0xA6 */
+
+/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */
+
+/**********************************************************************/
+
+/* Shared RAM Area */
+#define SCB_BASE               0x0000
+#define STATUS_BASE            0x0100
+#define HOST_TO_ECF_BASE       0x0200
+#define ECF_TO_HOST_BASE       0x0300
+#define CCS_BASE               0x0400
+#define RCS_BASE               0x0800
+#define INFRA_TIM_BASE         0x0C00
+#define SSID_LIST_BASE         0x0D00
+#define TX_BUF_BASE            0x1000
+#define RX_BUF_BASE            0x8000
+
+#define NUMBER_OF_CCS    64
+#define NUMBER_OF_RCS    64
+/*#define NUMBER_OF_TX_CCS 14 */
+#define NUMBER_OF_TX_CCS 14
+
+#define TX_BUF_SIZE      (2048 - sizeof(struct tx_msg))
+#define RX_BUFF_END      0x3FFF
+/* Values for buffer_status */
+#define CCS_BUFFER_FREE       0
+#define CCS_BUFFER_BUSY       1
+#define CCS_COMMAND_COMPLETE  2
+#define CCS_COMMAND_FAILED    3
+
+/* Values for cmd */
+#define CCS_DOWNLOAD_STARTUP_PARAMS    1
+#define CCS_UPDATE_PARAMS              2
+#define CCS_REPORT_PARAMS              3
+#define CCS_UPDATE_MULTICAST_LIST      4
+#define CCS_UPDATE_POWER_SAVINGS_MODE  5
+#define CCS_START_NETWORK              6
+#define CCS_JOIN_NETWORK               7
+#define CCS_START_ASSOCIATION          8
+#define CCS_TX_REQUEST                 9
+#define CCS_TEST_MEMORY              0xa
+#define CCS_SHUTDOWN                 0xb
+#define CCS_DUMP_MEMORY              0xc
+#define CCS_START_TIMER              0xe
+#define CCS_LAST_CMD                 CCS_START_TIMER
+
+/* Values for link field */
+#define CCS_END_LIST                 0xff
+
+/* values for buffer_status field */
+#define RCS_BUFFER_FREE       0
+#define RCS_BUFFER_BUSY       1
+#define RCS_COMPLETE          2
+#define RCS_FAILED            3
+#define RCS_BUFFER_RELEASE    0xFF
+
+/* values for interrupt_id field */
+#define PROCESS_RX_PACKET           0x80 /* */
+#define REJOIN_NET_COMPLETE         0x81 /* RCS ID: Rejoin Net Complete */
+#define ROAMING_INITIATED           0x82 /* RCS ID: Roaming Initiated   */
+#define JAPAN_CALL_SIGN_RXD         0x83 /* RCS ID: New Japan Call Sign */
+
+/*****************************************************************************/
+/* Memory types for dump memory command */
+#define C_MEM_PROG  0
+#define C_MEM_XDATA 1
+#define C_MEM_SFR   2
+#define C_MEM_IDATA 3
+
+/*** Return values for hw_xmit **********/
+#define XMIT_OK        (0)
+#define XMIT_MSG_BAD   (-1)
+#define XMIT_NO_CCS    (-2)
+#define XMIT_NO_INTR   (-3)
+#define XMIT_NEED_AUTH (-4)
+
+/*** Values for card status */
+#define CARD_INSERTED       (0)
+
+#define CARD_AWAITING_PARAM (1)
+#define CARD_INIT_ERROR     (11)
+
+#define CARD_DL_PARAM       (2)
+#define CARD_DL_PARAM_ERROR (12)
+
+#define CARD_DOING_ACQ      (3)
+
+#define CARD_ACQ_COMPLETE   (4)
+#define CARD_ACQ_FAILED     (14)
+
+#define CARD_AUTH_COMPLETE  (5)
+#define CARD_AUTH_REFUSED   (15)
+
+#define CARD_ASSOC_COMPLETE (6)
+#define CARD_ASSOC_FAILED   (16)
+
+/*** Values for authentication_state */
+#define UNAUTHENTICATED     (0)
+#define AWAITING_RESPONSE   (1)
+#define AUTHENTICATED       (2)
+#define NEED_TO_AUTH        (3)
+
+/*** Values for authentication type */
+#define OPEN_AUTH_REQUEST   (1)
+#define OPEN_AUTH_RESPONSE  (2)
+
+
+/***********************************************************************/
+/* Parameter passing structure for update/report parameter CCS's */
+struct object_id {
+    void          *object_addr;
+    unsigned char object_length;
+};
+
+#define OBJID_network_type            0
+#define OBJID_acting_as_ap_status     1
+#define OBJID_current_ess_id          2
+#define OBJID_scanning_mode           3
+#define OBJID_power_mgt_state         4
+#define OBJID_mac_address             5
+#define OBJID_frag_threshold          6
+#define OBJID_hop_time                7
+#define OBJID_beacon_period           8
+#define OBJID_dtim_period             9
+#define OBJID_retry_max              10
+#define OBJID_ack_timeout            11
+#define OBJID_sifs                   12
+#define OBJID_difs                   13
+#define OBJID_pifs                   14
+#define OBJID_rts_threshold          15
+#define OBJID_scan_dwell_time        16
+#define OBJID_max_scan_dwell_time    17
+#define OBJID_assoc_resp_timeout     18
+#define OBJID_adhoc_scan_cycle_max   19
+#define OBJID_infra_scan_cycle_max   20
+#define OBJID_infra_super_cycle_max  21
+#define OBJID_promiscuous_mode       22
+#define OBJID_unique_word            23
+#define OBJID_slot_time              24
+#define OBJID_roaming_low_snr        25
+#define OBJID_low_snr_count_thresh   26
+#define OBJID_infra_missed_bcn       27
+#define OBJID_adhoc_missed_bcn       28
+#define OBJID_curr_country_code      29
+#define OBJID_hop_pattern            30
+#define OBJID_reserved               31
+#define OBJID_cw_max_msb             32
+#define OBJID_cw_min_msb             33
+#define OBJID_noise_filter_gain      34
+#define OBJID_noise_limit_offset     35
+#define OBJID_det_rssi_thresh_offset 36
+#define OBJID_med_busy_thresh_offset 37
+#define OBJID_det_sync_thresh        38
+#define OBJID_test_mode              39
+#define OBJID_test_min_chan_num      40
+#define OBJID_test_max_chan_num      41
+#define OBJID_allow_bcast_ID_prbrsp  42
+#define OBJID_privacy_must_start     43
+#define OBJID_privacy_can_join       44
+#define OBJID_basic_rate_set         45
+
+/**** Configuration/Status/Control Area ***************************/
+/*    System Control Block (SCB) Area
+ *    Located at Shared RAM offset 0
+ */
+struct scb {
+    UCHAR ccs_index;
+    UCHAR rcs_index;
+};
+
+/****** Status area at Shared RAM offset 0x0100 ******************************/
+struct status {
+    UCHAR mrx_overflow_for_host;         /* 0=ECF may write, 1=host may write*/
+    UCHAR mrx_checksum_error_for_host;   /* 0=ECF may write, 1=host may write*/
+    UCHAR rx_hec_error_for_host;         /* 0=ECF may write, 1=host may write*/
+    UCHAR reserved1;
+    short mrx_overflow;                  /* ECF increments on rx overflow    */
+    short mrx_checksum_error;            /* ECF increments on rx CRC error   */
+    short rx_hec_error;                  /* ECF incs on mac header CRC error */
+    UCHAR rxnoise;                       /* Average RSL measurement          */
+};
+
+/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/
+struct host_to_ecf_area {
+    
+};
+
+/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/
+struct startup_res_518 {
+    UCHAR startup_word;
+    UCHAR station_addr[ADDRLEN];
+    UCHAR calc_prog_chksum;
+    UCHAR calc_cis_chksum;
+    UCHAR ecf_spare[7];
+    UCHAR japan_call_sign[12];
+};
+
+struct startup_res_6 {
+    UCHAR startup_word;
+    UCHAR station_addr[ADDRLEN];
+    UCHAR reserved;
+    UCHAR supp_rates[8];
+    UCHAR japan_call_sign[12];
+    UCHAR calc_prog_chksum;
+    UCHAR calc_cis_chksum;
+    UCHAR firmware_version[3];
+    UCHAR asic_version;
+    UCHAR tib_length;
+};
+
+struct start_join_net_params {
+    UCHAR net_type;
+    UCHAR ssid[ESSID_SIZE];
+    UCHAR reserved;
+    UCHAR privacy_can_join;
+};
+
+/****** Command Control Structure area at Shared ram offset 0x0400 ***********/
+/* Structures for command specific parameters (ccs.var) */
+struct update_param_cmd {
+    UCHAR object_id;
+    UCHAR number_objects;
+    UCHAR failure_cause;
+};
+struct report_param_cmd {
+    UCHAR object_id;
+    UCHAR number_objects;
+    UCHAR failure_cause;
+    UCHAR length;
+};
+struct start_network_cmd {
+    UCHAR update_param;
+    UCHAR bssid[ADDRLEN];
+    UCHAR net_initiated;
+    UCHAR net_default_tx_rate;
+    UCHAR encryption;
+};
+struct join_network_cmd {
+    UCHAR update_param;
+    UCHAR bssid[ADDRLEN];
+    UCHAR net_initiated;
+    UCHAR net_default_tx_rate;
+    UCHAR encryption;
+};
+struct tx_requested_cmd {
+ 
+    UCHAR tx_data_ptr[2];
+    UCHAR tx_data_length[2];
+    UCHAR host_reserved[2];
+    UCHAR reserved[3];
+    UCHAR tx_rate;
+    UCHAR pow_sav_mode;
+    UCHAR retries;
+    UCHAR antenna;
+};
+struct tx_requested_cmd_4 {
+ 
+    UCHAR tx_data_ptr[2];
+    UCHAR tx_data_length[2];
+    UCHAR dest_addr[ADDRLEN];
+    UCHAR pow_sav_mode;
+    UCHAR retries;
+    UCHAR station_id;
+};
+struct memory_dump_cmd {
+    UCHAR memory_type;
+    UCHAR memory_ptr[2];
+    UCHAR length;
+};
+struct update_association_cmd {
+    UCHAR status;
+    UCHAR aid[2];
+};
+struct start_timer_cmd {
+    UCHAR duration[2];
+};
+
+struct ccs {
+    UCHAR buffer_status;                 /* 0 = buffer free, 1 = buffer busy */
+                                         /* 2 = command complete, 3 = failed */
+    UCHAR cmd;                           /* command to ECF                   */
+    UCHAR link;                          /* link to next CCS, FF=end of list */
+    /* command specific parameters      */
+    union {
+        char reserved[13];
+        struct update_param_cmd update_param;
+        struct report_param_cmd report_param;
+        UCHAR nummulticast;
+        UCHAR mode;
+        struct start_network_cmd start_network;
+        struct join_network_cmd join_network;
+        struct tx_requested_cmd tx_request;
+        struct memory_dump_cmd memory_dump;
+        struct update_association_cmd update_assoc;
+        struct start_timer_cmd start_timer;
+    } var;
+};
+
+/*****************************************************************************/
+/* Transmit buffer structures */
+struct tib_structure {
+    UCHAR ccs_index;
+    UCHAR psm;
+    UCHAR pass_fail;
+    UCHAR retry_count;
+    UCHAR max_retries;
+    UCHAR frags_remaining;
+    UCHAR no_rb;
+    UCHAR rts_reqd;
+    UCHAR csma_tx_cntrl_2;
+    UCHAR sifs_tx_cntrl_2;
+    UCHAR tx_dma_addr_1[2];
+    UCHAR tx_dma_addr_2[2];
+    UCHAR var_dur_2mhz[2];
+    UCHAR var_dur_1mhz[2];
+    UCHAR max_dur_2mhz[2];
+    UCHAR max_dur_1mhz[2];
+    UCHAR hdr_len;
+    UCHAR max_frag_len[2];
+    UCHAR var_len[2];
+    UCHAR phy_hdr_4;
+    UCHAR mac_hdr_1;
+    UCHAR mac_hdr_2;
+    UCHAR sid[2];
+};
+
+struct phy_header {
+    UCHAR sfd[2];
+    UCHAR hdr_3;
+    UCHAR hdr_4;
+};
+struct rx_msg {
+    struct mac_header mac;
+    UCHAR  var[1];
+};
+
+struct tx_msg {
+    struct tib_structure tib;
+    struct phy_header phy;
+    struct mac_header mac;
+    UCHAR  var[1];
+};
+
+/****** ECF Receive Control Stucture (RCS) Area at Shared RAM offset 0x0800  */
+/* Structures for command specific parameters (rcs.var) */
+struct rx_packet_cmd {
+    UCHAR rx_data_ptr[2];
+    UCHAR rx_data_length[2];
+    UCHAR rx_sig_lev;
+    UCHAR next_frag_rcs_index;
+    UCHAR totalpacketlength[2];
+};
+struct rejoin_net_cmplt_cmd {
+    UCHAR reserved;
+    UCHAR bssid[ADDRLEN];
+};
+struct japan_call_sign_rxd {
+    UCHAR rxd_call_sign[8];
+    UCHAR reserved[5];
+};
+
+struct rcs {
+    UCHAR buffer_status;
+    UCHAR interrupt_id;
+    UCHAR link_field;
+    /* command specific parameters      */
+    union {
+        UCHAR reserved[13]; 
+        struct rx_packet_cmd rx_packet;
+        struct rejoin_net_cmplt_cmd rejoin_net_complete;
+        struct japan_call_sign_rxd japan_call_sign;
+    } var;
+};
+
+/****** Startup parameter structures for both versions of firmware ***********/
+struct b4_startup_params {
+    UCHAR a_network_type;                /* C_ADHOC, C_INFRA                 */
+    UCHAR a_acting_as_ap_status;         /* C_TYPE_STA, C_TYPE_AP            */
+    UCHAR a_current_ess_id[ESSID_SIZE];  /* Null terminated unless 32 long   */
+    UCHAR a_scanning_mode;               /* passive 0, active 1              */
+    UCHAR a_power_mgt_state;             /* CAM 0,                           */
+    UCHAR a_mac_addr[ADDRLEN];           /*                                  */
+    UCHAR a_frag_threshold[2];           /* 512                              */
+    UCHAR a_hop_time[2];                 /* 16k * 2**n, n=0-4 in Kus         */
+    UCHAR a_beacon_period[2];            /* n * a_hop_time  in Kus           */
+    UCHAR a_dtim_period;                 /* in beacons                       */
+    UCHAR a_retry_max;                   /*                                  */
+    UCHAR a_ack_timeout;                 /*                                  */
+    UCHAR a_sifs;                        /*                                  */
+    UCHAR a_difs;                        /*                                  */
+    UCHAR a_pifs;                        /*                                  */
+    UCHAR a_rts_threshold[2];            /*                                  */
+    UCHAR a_scan_dwell_time[2];          /*                                  */
+    UCHAR a_max_scan_dwell_time[2];      /*                                  */
+    UCHAR a_assoc_resp_timeout_thresh;   /*                                  */
+    UCHAR a_adhoc_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_super_scan_cycle_max;  /*                                  */
+    UCHAR a_promiscuous_mode;            /*                                  */
+    UCHAR a_unique_word[2];              /*                                  */
+    UCHAR a_slot_time;                   /*                                  */
+    UCHAR a_roaming_low_snr_thresh;      /*                                  */
+    UCHAR a_low_snr_count_thresh;        /*                                  */
+    UCHAR a_infra_missed_bcn_thresh;     /*                                  */
+    UCHAR a_adhoc_missed_bcn_thresh;     /*                                  */
+    UCHAR a_curr_country_code;           /* C_USA                            */
+    UCHAR a_hop_pattern;                 /*                                  */
+    UCHAR a_hop_pattern_length;          /*                                  */
+/* b4 - b5 differences start here */
+    UCHAR a_cw_max;                      /*                                  */
+    UCHAR a_cw_min;                      /*                                  */
+    UCHAR a_noise_filter_gain;           /*                                  */
+    UCHAR a_noise_limit_offset;          /*                                  */
+    UCHAR a_det_rssi_thresh_offset;      /*                                  */
+    UCHAR a_med_busy_thresh_offset;      /*                                  */
+    UCHAR a_det_sync_thresh;             /*                                  */
+    UCHAR a_test_mode;                   /*                                  */
+    UCHAR a_test_min_chan_num;           /*                                  */
+    UCHAR a_test_max_chan_num;           /*                                  */
+    UCHAR a_rx_tx_delay;                 /*                                  */
+    UCHAR a_current_bss_id[ADDRLEN];     /*                                  */
+    UCHAR a_hop_set;                     /*                                  */
+};
+struct b5_startup_params {
+    UCHAR a_network_type;                /* C_ADHOC, C_INFRA                 */
+    UCHAR a_acting_as_ap_status;         /* C_TYPE_STA, C_TYPE_AP            */
+    UCHAR a_current_ess_id[ESSID_SIZE];  /* Null terminated unless 32 long   */
+    UCHAR a_scanning_mode;               /* passive 0, active 1              */
+    UCHAR a_power_mgt_state;             /* CAM 0,                           */
+    UCHAR a_mac_addr[ADDRLEN];           /*                                  */
+    UCHAR a_frag_threshold[2];           /* 512                              */
+    UCHAR a_hop_time[2];                 /* 16k * 2**n, n=0-4 in Kus         */
+    UCHAR a_beacon_period[2];            /* n * a_hop_time  in Kus           */
+    UCHAR a_dtim_period;                 /* in beacons                       */
+    UCHAR a_retry_max;                   /* 4                                */
+    UCHAR a_ack_timeout;                 /*                                  */
+    UCHAR a_sifs;                        /*                                  */
+    UCHAR a_difs;                        /*                                  */
+    UCHAR a_pifs;                        /*                                  */
+    UCHAR a_rts_threshold[2];            /*                                  */
+    UCHAR a_scan_dwell_time[2];          /*                                  */
+    UCHAR a_max_scan_dwell_time[2];      /*                                  */
+    UCHAR a_assoc_resp_timeout_thresh;   /*                                  */
+    UCHAR a_adhoc_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_super_scan_cycle_max;  /*                                  */
+    UCHAR a_promiscuous_mode;            /*                                  */
+    UCHAR a_unique_word[2];              /*                                  */
+    UCHAR a_slot_time;                   /*                                  */
+    UCHAR a_roaming_low_snr_thresh;      /*                                  */
+    UCHAR a_low_snr_count_thresh;        /*                                  */
+    UCHAR a_infra_missed_bcn_thresh;     /*                                  */
+    UCHAR a_adhoc_missed_bcn_thresh;     /*                                  */
+    UCHAR a_curr_country_code;           /* C_USA                            */
+    UCHAR a_hop_pattern;                 /*                                  */
+    UCHAR a_hop_pattern_length;          /*                                  */
+/* b4 - b5 differences start here */
+    UCHAR a_cw_max[2];                   /*                                  */
+    UCHAR a_cw_min[2];                   /*                                  */
+    UCHAR a_noise_filter_gain;           /*                                  */
+    UCHAR a_noise_limit_offset;          /*                                  */
+    UCHAR a_det_rssi_thresh_offset;      /*                                  */
+    UCHAR a_med_busy_thresh_offset;      /*                                  */
+    UCHAR a_det_sync_thresh;             /*                                  */
+    UCHAR a_test_mode;                   /*                                  */
+    UCHAR a_test_min_chan_num;           /*                                  */
+    UCHAR a_test_max_chan_num;           /*                                  */
+    UCHAR a_allow_bcast_SSID_probe_rsp;
+    UCHAR a_privacy_must_start;
+    UCHAR a_privacy_can_join;
+    UCHAR a_basic_rate_set[8];
+};
+
+/*****************************************************************************/
+#define RAY_IOCG_PARMS (SIOCDEVPRIVATE)
+#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1)
+#define RAY_DO_CMD     (SIOCDEVPRIVATE + 2)
+
+/****** ethernet <-> 802.11 translation **************************************/
+typedef struct snaphdr_t
+{
+  UCHAR   dsap;
+  UCHAR   ssap;
+  UCHAR   ctrl;
+  UCHAR   org[3];
+  UCHAR   ethertype[2];
+} snaphdr_t;
+
+#define BRIDGE_ENCAP  0xf80000
+#define RFC1042_ENCAP 0
+#define SNAP_ID       0x0003aaaa
+#define RAY_IPX_TYPE  0x8137
+#define APPLEARP_TYPE 0x80f3
+/*****************************************************************************/
+#endif /* #ifndef RAYLINK_H */
diff -u --recursive --new-file v2.3.17/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.3.17/linux/drivers/net/plip.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/plip.c	Wed Sep  8 11:51:22 1999
@@ -113,10 +113,10 @@
 
 #include <linux/tqueue.h>
 #include <linux/ioport.h>
+#include <linux/spinlock.h>
 #include <asm/bitops.h>
 #include <asm/irq.h>
 #include <asm/byteorder.h>
-#include <asm/spinlock.h>
 #include <asm/semaphore.h>
 
 #include <linux/parport.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.3.17/linux/drivers/net/ppp_generic.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/ppp_generic.c	Wed Sep  8 11:51:22 1999
@@ -40,8 +40,8 @@
 #include <linux/if_arp.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <linux/spinlock.h>
 #include <net/slhc_vj.h>
-#include <asm/spinlock.h>
 
 #define PPP_VERSION	"2.4.0"
 
diff -u --recursive --new-file v2.3.17/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.3.17/linux/drivers/net/rtl8139.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/rtl8139.c	Wed Sep  8 11:14:32 1999
@@ -424,13 +424,15 @@
 	/* Bring the chip out of low-power mode. */
 	outb(0x00, ioaddr + Config1);
 
-	if (read_eeprom(ioaddr, 0) != 0xffff)
-		for (i = 0; i < 3; i++)
-			((u16 *)(dev->dev_addr))[i] = read_eeprom(ioaddr, i + 7);
-	else
+	if (read_eeprom(ioaddr, 0) != 0xffff) {
+		for (i = 0; i < 3; i++) {
+			((u16 *)(dev->dev_addr))[i] =
+				le16_to_cpu(read_eeprom(ioaddr, i + 7));
+		}
+	} else {
 		for (i = 0; i < 6; i++)
 			dev->dev_addr[i] = inb(ioaddr + MAC0 + i);
-
+	}
 	for (i = 0; i < 5; i++)
 		printk("%2.2x:", dev->dev_addr[i]);
 	printk("%2.2x.\n", dev->dev_addr[i]);
@@ -1188,7 +1190,7 @@
 
 	while ((inb(ioaddr + ChipCmd) & 1) == 0) {
 		int ring_offset = cur_rx % RX_BUF_LEN;
-		u32 rx_status = *(u32*)(rx_ring + ring_offset);
+		u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset));
 		int rx_size = rx_status >> 16;
 
 		if (rtl8129_debug > 4) {
@@ -1197,7 +1199,7 @@
 				   dev->name, rx_status, rx_size, cur_rx);
 			printk(KERN_DEBUG"%s: Frame contents ", dev->name);
 			for (i = 0; i < 70; i++)
-				printk(" %2.2x", rx_ring[ring_offset + i]);
+				printk(" %2.2x", le32_to_cpu(rx_ring[ring_offset + i]));
 			printk(".\n");
 		}
 		if (rx_status & RxTooLong) {
@@ -1248,7 +1250,7 @@
 					printk(KERN_DEBUG"%s:  Frame wrap @%d",
 						   dev->name, semi_count);
 					for (i = 0; i < 16; i++)
-						printk(" %2.2x", rx_ring[i]);
+						printk(" %2.2x", le32_to_cpu(rx_ring[i]));
 					printk(".\n");
 					memset(rx_ring, 0xcc, 16);
 				}
diff -u --recursive --new-file v2.3.17/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.3.17/linux/drivers/net/starfire.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/starfire.c	Wed Sep  8 11:14:32 1999
@@ -0,0 +1,1431 @@
+/* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */
+/*
+	Written 1998-1999 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License (GPL), incorporated herein by reference.
+
+	The author may be reached as becker@usra.edu, or
+	Donald Becker
+	312 Severn Ave. #W302
+	Annapolis MD 21403
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/starfire.html
+*/
+
+static const char *versionA =
+"starfire.c:v0.12 5/28/99  Written by Donald Becker\n",
+*versionB =" Undates and info at http://www.beowulf.org/linux/drivers.html\n";
+
+/* A few user-configurable values.   These may be modified when a driver
+   module is loaded.*/
+
+/* Used for tuning interrupt latency vs. overhead. */
+static int interrupt_mitigation = 0x0;
+
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+static int max_interrupt_work = 20;
+static int min_pci_latency = 64;
+static int mtu = 0;
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
+   The Starfire has a 512 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static int rx_copybreak = 0;
+
+/* Used to pass the media type, etc.
+   Both 'options[]' and 'full_duplex[]' exist for driver interoperability.
+   The media type is usually passed in 'options[]'.
+*/
+#define MAX_UNITS 8		/* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Operational parameters that are set at compile time. */
+
+/* The "native" ring sizes are either 256 or 2048.
+   However in some modes a descriptor may be marked to wrap the ring earlier.
+   The driver allocates a single page for each descriptor ring, constraining
+   the maximum size in an architecture-dependent way.
+*/
+#define RX_RING_SIZE	256
+#define TX_RING_SIZE	32
+/* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */
+#define DONE_Q_SIZE	1024
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+/* Include files, designed to support most kernel versions 2.0.0 and later. */
+#include <linux/config.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
+   This is only in the support-all-kernels source code. */
+
+#define RUN_AT(x) (jiffies + (x))
+
+#ifdef MODULE
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(min_pci_latency, "i");
+MODULE_PARM(mtu, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+#endif
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+State the chips and boards this driver is known to work with.
+Note any similar chips or boards that will not work.
+
+This driver skeleton demonstrates the driver for an idealized
+descriptor-based bus-master PCI chip.
+
+II. Board-specific settings
+
+No jumpers exist on most PCI boards, so this section is usually empty.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Starfire hardware uses multiple fixed-size descriptor queues/rings.  The
+ring sizes are set fixed by the hardware, but may optionally be wrapped
+earlier by the END bit in the descriptor.
+This driver uses that hardware queue size for the Rx ring, where a large
+number of entries has no ill effect beyond increases the potential backlog.
+The Tx ring is wrapped with the END bit, since a large hardware Tx queue
+disables the queue layer priority ordering and we have no mechanism to
+utilize the hardware two-level priority queue.  When modifying the
+RX/TX_RING_SIZE pay close attention to page sizes and the ring-empty warning
+levels.
+
+IIIb/c. Transmit/Receive Structure
+
+See the Adaptec manual for the many possible structures, and options for
+each structure.  There are far too many to document here.
+
+For transmit this driver uses type 1 transmit descriptors, and relies on
+automatic minimum-length padding.  It does not use the completion queue
+consumer index, but instead checks for non-zero status entries.
+
+For receive this driver uses type 0 receive descriptors.  The driver
+allocates full frame size skbuffs for the Rx ring buffers, so all frames
+should fit in a single descriptor.  The driver does not use the completion
+queue consumer index, but instead checks for non-zero status entries.
+
+When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuff
+is allocated and the frame is copied to the new skbuff.  When the incoming
+frame is larger, the skbuff is passed directly up the protocol stack.
+Buffers consumed this way are replaced by newly allocated skbuffs in a later
+phase of receive.
+
+A notable aspect of operation is that unaligned buffers are not permitted by
+the Starfire hardware.  The IP header at offset 14 in an ethernet frame thus
+isn't longword aligned, which may cause problems on some machine
+e.g. Alphas.  Copied frames are put into the skbuff at an offset of "+2",
+16-byte aligning the IP header.
+
+IIId. Synchronization
+
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and interrupt handling software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'lp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+IVb. References
+
+The Adaptec Starfire manuals.
+http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+
+
+IVc. Errata
+
+*/
+
+
+
+/* This table drives the PCI probe routines.  It's mostly boilerplate in all
+   PCI drivers, and will likely be provided by some future kernel.
+*/
+enum pci_flags_bit {
+	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+struct pci_id_info {
+	const char *name;
+	u16	vendor_id, device_id, device_id_mask, flags;
+	int io_size;
+	struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
+								 long ioaddr, int irq, int chip_idx, int fnd_cnt);
+};
+
+static struct net_device *starfire_probe1(int pci_bus, int pci_devfn,
+									  struct net_device *dev, long ioaddr,
+									  int irq, int chp_idx, int fnd_cnt);
+
+#if 0
+#define ADDR_64BITS 1			/* This chip uses 64 bit addresses. */
+#endif
+#define MEM_ADDR_SZ 0x80000		/* And maps in 0.5MB(!).  */
+
+static struct pci_id_info pci_tbl[] = {
+	{ "Adaptec Starfire 6915",
+	  0x9004, 0x6915, 0xffff, PCI_USES_MASTER, 128, starfire_probe1},
+	{0,},						/* 0 terminated list. */
+};
+
+
+/* A chip capabilities table, matching the entries in pci_tbl[] above. */
+enum chip_capability_flags {CanHaveMII=1, };
+struct chip_info {
+	char *chip_name;
+	int io_size;
+	int flags;
+	void (*media_timer)(unsigned long data);
+} static skel_netdrv_tbl[] = {
+	{"Adaptec Starfire 6915", 128, CanHaveMII, 0, },
+};
+
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum register_offsets {
+	PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074,
+	IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088,
+	MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000,
+	TxDescCtrl=0x50090,
+	TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */
+	TxRingHiAddr=0x5009C,		/* 64 bit address extension. */
+	TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4,
+	TxThreshold=0x500B0,
+	CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8,
+	RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0,
+	CompletionQConsumerIdx=0x500C4,
+	RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0,
+	RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4,
+	TxMode=0x55000,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+	IntrNormalSummary=0x8000,	IntrAbnormalSummary=0x02000000,
+	IntrRxDone=0x0300, IntrRxEmpty=0x10040, IntrRxPCIErr=0x80000,
+	IntrTxDone=0x4000, IntrTxEmpty=0x1000, IntrTxPCIErr=0x80000,
+	StatsMax=0x08000000, LinkChange=0xf0000000,
+	IntrTxDataLow=0x00040000,
+};
+
+/* Bits in the RxFilterMode register. */
+enum rx_mode_bits {
+	AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01,
+	AcceptMulticast=0x10, AcceptMyPhys=0xE040,
+};
+
+/* The Rx and Tx buffer descriptors. */
+struct starfire_rx_desc {
+	u32 rxaddr;					/* Optionally 64 bits. */
+};
+enum rx_desc_bits {
+	RxDescValid=1, RxDescEndRing=2,
+};
+
+/* Completion queue entry.
+   You must update the page allocation, init_ring and the shift count in rx()
+   if using a larger format. */
+struct rx_done_desc {
+	u32 status;					/* Low 16 bits is length. */
+#ifdef full_rx_status
+	u32 status2;
+	u16 vlanid;
+	u16 csum; 			/* partial checksum */
+	u32 timestamp;
+#endif
+};
+enum rx_done_bits {
+	RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
+};
+
+/* Type 1 Tx descriptor. */
+struct starfire_tx_desc {
+	u32 status;					/* Upper bits are status, lower 16 length. */
+	u32 addr;
+};
+enum tx_desc_bits {
+	TxDescID=0xB1010000,		/* Also marks single fragment, add CRC.  */
+	TxDescIntr=0x08000000, TxRingWrap=0x04000000,
+};
+struct tx_done_report {
+	u32 status;					/* timestamp, index. */
+#if 0
+	u32 intrstatus;				/* interrupt status */
+#endif
+};
+
+struct netdev_private {
+	/* Descriptor rings first for alignment. */
+	struct starfire_rx_desc *rx_ring;
+	struct starfire_tx_desc *tx_ring;
+	struct net_device *next_module;			/* Link for devices of this type. */
+	const char *product_name;
+	/* The addresses of rx/tx-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	/* Pointers to completion queues (full pages).  I should cache line pad..*/
+	u8 pad0[100];
+	struct rx_done_desc *rx_done_q;
+	unsigned int rx_done;
+	struct tx_done_report *tx_done_q;
+	unsigned int tx_done;
+	struct net_device_stats stats;
+	struct timer_list timer;	/* Media monitoring timer. */
+	/* Frequently used values: keep some adjacent for cache effect. */
+	int chip_id;
+	unsigned char pci_bus, pci_devfn;
+	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	unsigned int cur_tx, dirty_tx;
+	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	/* These values are keep track of the transceiver/media in use. */
+	unsigned int duplex_lock:1;
+	unsigned int full_duplex:1,			/* Full-duplex operation requested. */
+		rx_flowctrl:1,
+		tx_flowctrl:1;					/* Use 802.3x flow control. */
+	unsigned int medialock:1;			/* Do not sense media. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	u32 tx_mode;
+	u8 tx_threshold;
+	/* MII transceiver section. */
+	int mii_cnt;						/* MII device addresses. */
+	u16 advertising;					/* NWay media advertisement */
+	unsigned char phys[2];				/* MII device addresses. */
+	u32 pad[4];							/* Used for 32-byte alignment */
+};
+
+static int  mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static int  netdev_open(struct net_device *dev);
+static void check_duplex(struct net_device *dev, int startup);
+static void netdev_timer(unsigned long data);
+static void tx_timeout(struct net_device *dev);
+static void init_ring(struct net_device *dev);
+static int  start_tx(struct sk_buff *skb, struct net_device *dev);
+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static void netdev_error(struct net_device *dev, int intr_status);
+static int  netdev_rx(struct net_device *dev);
+static void netdev_error(struct net_device *dev, int intr_status);
+static void set_rx_mode(struct net_device *dev);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int  netdev_close(struct net_device *dev);
+
+
+
+/* A list of our installed devices, for removing the driver module. */
+static struct net_device *root_net_dev = NULL;
+
+/* Ideally we would detect all network cards in slot order.  That would
+   be best done a central PCI probe dispatch, which wouldn't work
+   well when dynamically adding drivers.  So instead we detect just the
+   cards we know about in slot order. */
+
+static int pci_etherdev_probe(struct net_device *dev, struct pci_id_info pci_tbl[])
+{
+	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, irq;
+		long pciaddr;
+		long ioaddr;
+
+		if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
+								&pci_bus, &pci_device_fn)
+			!= PCIBIOS_SUCCESSFUL)
+			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) 		/* Compiled out! */
+			continue;
+
+		{
+			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+
+			pciaddr = pdev->resource[0].start;
+#if defined(ADDR_64BITS) && defined(__alpha__)
+			pciaddr |= ((long)pdev->base_address[1]) << 32;
+#endif
+			irq = pdev->irq;
+		}
+
+		if (debug > 2)
+			printk(KERN_INFO "Found %s at PCI address %#lx, IRQ %d.\n",
+				   pci_tbl[chip_idx].name, pciaddr, irq);
+
+		if ((pci_tbl[chip_idx].flags & PCI_USES_IO)) {
+			if (check_region(pciaddr, pci_tbl[chip_idx].io_size))
+				continue;
+			ioaddr = pciaddr;
+		} else if ((ioaddr = (long)ioremap(pciaddr&~0xf, MEM_ADDR_SZ)) == 0) {
+			printk(KERN_INFO "Failed to map PCI address %#lx.\n",
+				   pciaddr);
+			continue;
+		}
+
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_COMMAND, &pci_command);
+		new_command = pci_command | (pci_tbl[chip_idx].flags & 7);
+		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);
+
+		if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
+			u8 pci_latency;
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_LATENCY_TIMER, &pci_latency);
+			if (pci_latency < min_pci_latency) {
+				printk(KERN_INFO "  PCI latency timer (CFLT) is "
+					   "unreasonably low at %d.  Setting to %d clocks.\n",
+					   pci_latency, min_pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, min_pci_latency);
+			}
+		}
+		dev = 0;
+		cards_found++;
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+
+int starfire_probe(struct net_device *dev)
+{
+	if (pci_etherdev_probe(dev, pci_tbl) < 0)
+		return -ENODEV;
+	printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+	return 0;
+}
+
+
+static struct net_device *
+starfire_probe1(int pci_bus, int pci_devfn, struct net_device *dev,
+				long ioaddr, int irq, int chip_id, int card_idx)
+{
+	struct netdev_private *np;
+	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+
+	dev = init_etherdev(dev, sizeof(struct netdev_private));
+
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+		   dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
+
+	/* Serial EEPROM reads are hidden by the hardware. */
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i);
+	for (i = 0; i < 5; i++)
+			printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+#if ! defined(final_version) /* Dump the EEPROM contents during development. */
+	if (debug > 4)
+		for (i = 0; i < 0x20; i++)
+			printk("%2.2x%s", readb(ioaddr + EEPROMCtrl + i),
+				   i % 16 != 15 ? " " : "\n");
+#endif
+
+	/* Reset the chip to erase previous misconfiguration. */
+	writel(1, ioaddr + PCIDeviceConfig);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	/* Make certain the descriptor lists are aligned. */
+	np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 15) & ~15);
+	memset(np, 0, sizeof(*np));
+	dev->priv = np;
+
+	np->next_module = root_net_dev;
+	root_net_dev = dev;
+
+	np->pci_bus = pci_bus;
+	np->pci_devfn = pci_devfn;
+	np->chip_id = chip_id;
+
+	if (dev->mem_start)
+		option = dev->mem_start;
+
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		if (option & 0x200)
+			np->full_duplex = 1;
+		np->default_port = option & 15;
+		if (np->default_port)
+			np->medialock = 1;
+	}
+	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
+		np->full_duplex = 1;
+
+	if (np->full_duplex)
+		np->duplex_lock = 1;
+
+	/* The chip-specific entries in the device structure. */
+	dev->open = &netdev_open;
+	dev->hard_start_xmit = &start_tx;
+	dev->stop = &netdev_close;
+	dev->get_stats = &get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &mii_ioctl;
+
+	if (mtu)
+		dev->mtu = mtu;
+
+	if (skel_netdrv_tbl[np->chip_id].flags & CanHaveMII) {
+		int phy, phy_idx = 0;
+		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				np->phys[phy_idx++] = phy;
+				np->advertising = mdio_read(dev, phy, 4);
+				printk(KERN_INFO "%s: MII PHY found at address %d, status "
+					   "0x%4.4x advertising %4.4x.\n",
+					   dev->name, phy, mii_status, np->advertising);
+			}
+		}
+		np->mii_cnt = phy_idx;
+	}
+
+	return dev;
+}
+
+
+/* Read the MII Management Data I/O (MDIO) interfaces. */
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+	int result, boguscnt=1000;
+	/* ??? Must add a busy-wait here. */
+	do
+		result = readl(mdio_addr);
+	while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);
+	return result & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+	writel(value, mdio_addr);
+	/* The busy-wait will occur before a read. */
+	return;
+}
+
+
+static int netdev_open(struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	/* Do we need to reset the chip??? */
+
+	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
+		return -EAGAIN;
+
+	/* Disable the Rx and Tx, and reset the chip. */
+	writel(0, ioaddr + GenCtrl);
+	writel(1, ioaddr + PCIDeviceConfig);
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
+			   dev->name, dev->irq);
+	/* Allocate the various queues, failing gracefully. */
+	if (np->tx_done_q == 0)
+		np->tx_done_q = (struct tx_done_report *)get_free_page(GFP_KERNEL);
+	if (np->rx_done_q == 0)
+		np->rx_done_q = (struct rx_done_desc *)get_free_page(GFP_KERNEL);
+	if (np->tx_ring == 0)
+		np->tx_ring = (struct starfire_tx_desc *)get_free_page(GFP_KERNEL);
+	if (np->rx_ring == 0)
+		np->rx_ring = (struct starfire_rx_desc *)get_free_page(GFP_KERNEL);
+	if (np->tx_done_q == 0  ||  np->rx_done_q == 0
+		|| np->rx_ring == 0 ||  np->tx_ring == 0)
+		return -ENOMEM;
+
+	MOD_INC_USE_COUNT;
+
+	init_ring(dev);
+	/* Set the size of the Rx buffers. */
+	writel((np->rx_buf_sz<<16) | 0xA000, ioaddr + RxDescQCtrl);
+
+	/* Set Tx descriptor to type 1 and padding to 0 bytes. */
+	writel(0x02000401, ioaddr + TxDescCtrl);
+
+#if defined(ADDR_64BITS) && defined(__alpha__)
+	writel(virt_to_bus(np->rx_ring) >> 32, ioaddr + RxDescQHiAddr);
+	writel(virt_to_bus(np->tx_ring) >> 32, ioaddr + TxRingHiAddr);
+#else
+	writel(0, ioaddr + RxDescQHiAddr);
+	writel(0, ioaddr + TxRingHiAddr);
+	writel(0, ioaddr + CompletionHiAddr);
+#endif
+	writel(virt_to_bus(np->rx_ring), ioaddr + RxDescQAddr);
+	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);
+
+	writel(virt_to_bus(np->tx_done_q), ioaddr + TxCompletionAddr);
+	writel(virt_to_bus(np->rx_done_q), ioaddr + RxCompletionAddr);
+
+	if (debug > 1)
+		printk(KERN_DEBUG "%s:  Filling in the station address.\n", dev->name);
+
+	/* Fill both the unused Tx SA register and the Rx perfect filter. */
+	for (i = 0; i < 6; i++)
+		writeb(dev->dev_addr[i], ioaddr + StationAddr + 6-i);
+	for (i = 0; i < 16; i++) {
+		u16 *eaddrs = (u16 *)dev->dev_addr;
+		long setup_frm = ioaddr + 0x56000 + i*16;
+		writew(eaddrs[0], setup_frm); setup_frm += 4;
+		writew(eaddrs[1], setup_frm); setup_frm += 4;
+		writew(eaddrs[2], setup_frm); setup_frm += 4;
+	}
+
+	/* Initialize other registers. */
+	/* Configure the PCI bus bursts and FIFO thresholds. */
+	np->tx_threshold = 4;
+	writel(np->tx_threshold, ioaddr + TxThreshold);
+	writel(interrupt_mitigation, ioaddr + IntrTimerCtrl);
+
+	if (dev->if_port == 0)
+		dev->if_port = np->default_port;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+
+	if (debug > 1)
+		printk(KERN_DEBUG "%s:  Setting the Rx and Tx modes.\n", dev->name);
+	set_rx_mode(dev);
+
+	check_duplex(dev, 1);
+
+	dev->start = 1;
+
+	/* Set the interrupt mask and enable PCI interrupts. */
+	writel(IntrRxDone | IntrRxEmpty | IntrRxPCIErr |
+		   IntrTxDone | IntrTxEmpty | IntrTxPCIErr |
+		   StatsMax | LinkChange | IntrNormalSummary | IntrAbnormalSummary
+		   | 0x0010 , ioaddr + IntrEnable);
+	writel(0x00800000 | readl(ioaddr + PCIDeviceConfig),
+		   ioaddr + PCIDeviceConfig);
+
+	/* Enable the Rx and Tx units. */
+	writel(0x000F, ioaddr + GenCtrl);
+
+	if (debug > 2)
+		printk(KERN_DEBUG "%s: Done netdev_open().\n",
+			   dev->name);
+
+	/* Set the timer to check for link beat. */
+	init_timer(&np->timer);
+	np->timer.expires = RUN_AT(3*HZ);
+	np->timer.data = (unsigned long)dev;
+	np->timer.function = &netdev_timer;				/* timer handler */
+	add_timer(&np->timer);
+
+	return 0;
+}
+
+static void check_duplex(struct net_device *dev, int startup)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+	int duplex, new_tx_mode ;
+
+	new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0) | (np->rx_flowctrl ? 0x0400:0);
+	if (np->duplex_lock)
+		duplex = 1;
+	else
+		duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+	if (duplex)
+		new_tx_mode |= 2;
+	if (np->full_duplex != duplex) {
+		np->full_duplex = duplex;
+		if (debug)
+			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
+				   " partner capability of %4.4x.\n", dev->name,
+				   duplex ? "full" : "half", np->phys[0], mii_reg5);
+	}
+	if (new_tx_mode != np->tx_mode) {
+		np->tx_mode = new_tx_mode;
+		writel(np->tx_mode | 0x8000, ioaddr + TxMode);
+		writel(np->tx_mode, ioaddr + TxMode);
+	}
+}
+
+static void netdev_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;		/* Check before driver release. */
+
+	if (debug > 3) {
+		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",
+			   dev->name, readl(ioaddr + IntrStatus));
+	}
+	check_duplex(dev, 0);
+#if ! defined(final_version)
+	/* This is often falsely triggered. */
+	if (readl(ioaddr + IntrStatus) & 1) {
+		int new_status = readl(ioaddr + IntrStatus);
+		/* Bogus hardware IRQ: Fake an interrupt handler call. */
+		if (new_status & 1) {
+			printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n",
+				   dev->name, new_status, readl(ioaddr + IntrStatus));
+			intr_handler(dev->irq, dev, 0);
+		}
+	}
+#endif
+
+	np->timer.expires = RUN_AT(next_tick);
+	add_timer(&np->timer);
+}
+
+static void tx_timeout(struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
+		   " resetting...\n", dev->name, readl(ioaddr + IntrStatus));
+
+#ifndef __alpha__
+	{
+		int i;
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)le32_to_cpu(np->rx_ring[i].rxaddr));
+		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %4.4x", le32_to_cpu(np->tx_ring[i].status));
+		printk("\n");
+	}
+#endif
+
+  /* Perhaps we should reinitialize the hardware here. */
+  dev->if_port = 0;
+  /* Stop and restart the chip's Tx processes . */
+
+  /* Trigger an immediate transmit demand. */
+
+  dev->trans_start = jiffies;
+  np->stats.tx_errors++;
+  return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void init_ring(struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	int i;
+
+	np->tx_full = 0;
+	np->cur_rx = np->cur_tx = 0;
+	np->dirty_rx = np->rx_done = np->dirty_tx = np->tx_done = 0;
+
+	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+		np->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;			/* Mark as being used by this device. */
+		/* Grrr, we cannot offset to correctly align the IP header. */
+		np->rx_ring[i].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid);
+	}
+	writew(i-1, dev->base_addr + RxDescQIdx);
+	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+	/* Clear the remainder of the Rx buffer ring. */
+	for (  ; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rxaddr = 0;
+		np->rx_skbuff[i] = 0;
+	}
+	/* Mark the last entry as wrapping the ring. */
+	np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing);
+
+	/* Clear the completion rings. */
+	for (i = 0; i < DONE_Q_SIZE; i++) {
+		np->rx_done_q[i].status = 0;
+		np->tx_done_q[i].status = 0;
+	}
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_skbuff[i] = 0;
+		np->tx_ring[i].status = 0;
+	}
+	return;
+}
+
+static int start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	unsigned entry;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		if (jiffies - dev->trans_start < TX_TIMEOUT)
+			return 1;
+		tx_timeout(dev);
+		return 1;
+	}
+
+	/* Caution: the write order is important here, set the field
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = np->cur_tx % TX_RING_SIZE;
+
+	np->tx_skbuff[entry] = skb;
+
+	np->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data));
+	/* Add  |TxDescIntr to generate Tx-done interrupts. */
+	np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID);
+	if (debug > 5) {
+		printk(KERN_DEBUG "%s: Tx #%d slot %d  %8.8x %8.8x.\n",
+			   dev->name, np->cur_tx, entry,
+			   le32_to_cpu(np->tx_ring[entry].status),
+			   le32_to_cpu(np->tx_ring[entry].addr));
+	}
+	np->cur_tx++;
+#if 1
+	if (entry >= TX_RING_SIZE-1) {		 /* Wrap ring */
+		np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
+		entry = -1;
+	}
+#endif
+
+	/* Non-x86: explicitly flush descriptor cache lines here. */
+
+	/* Update the producer index. */
+	writel(++entry, dev->base_addr + TxProducerIdx);
+
+	if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1)
+		np->tx_full = 1;
+	if (! np->tx_full)
+		clear_bit(0, (void*)&dev->tbusy);
+	dev->trans_start = jiffies;
+
+	if (debug > 4) {
+		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
+			   dev->name, np->cur_tx, entry);
+	}
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct netdev_private *np;
+	long ioaddr, boguscnt = max_interrupt_work;
+
+#ifndef final_version			/* Can never occur. */
+	if (dev == NULL) {
+		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
+				"device.\n", irq);
+		return;
+	}
+#endif
+
+	ioaddr = dev->base_addr;
+	np = (struct netdev_private *)dev->priv;
+#if defined(__i386__)
+	/* A lock to prevent simultaneous entry bug on Intel SMP machines. */
+	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
+		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
+			   dev->name);
+		dev->interrupt = 0;	/* Avoid halting machine. */
+		return;
+	}
+#else
+	if (dev->interrupt) {
+		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
+		return;
+	}
+	dev->interrupt = 1;
+#endif
+
+	do {
+		u32 intr_status = readl(ioaddr + IntrClear);
+
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n",
+				   dev->name, intr_status);
+
+		if (intr_status == 0)
+			break;
+
+		if (intr_status & IntrRxDone)
+			netdev_rx(dev);
+
+		/* Scavenge the skbuff list based on the Tx-done queue.
+		   There are redundant checks here that may be cleaned up when
+		   after the driver has proven reliable. */
+		{
+			int consumer = readl(ioaddr + TxConsumerIdx);
+			int tx_status;
+			if (debug > 4)
+				printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n",
+					   dev->name, consumer);
+#if 0
+			if (np->tx_done >= 250  || np->tx_done == 0)
+				printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, "
+					   "%d is %8.8x.\n", dev->name,
+					   np->tx_done, le32_to_cpu(np->tx_done_q[np->tx_done].status),
+					   (np->tx_done+1) & (DONE_Q_SIZE-1),
+					   le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
+#endif
+			while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) {
+				if (debug > 4)
+					printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
+						   dev->name, np->tx_done, tx_status);
+				if ((tx_status & 0xe0000000) == 0xa0000000) {
+					np->stats.tx_packets++;
+				} else if ((tx_status & 0xe0000000) == 0x80000000) {
+					u16 entry = tx_status; 		/* Implicit truncate */
+					entry >>= 3;
+					/* Scavenge the descriptor. */
+					dev_kfree_skb(np->tx_skbuff[entry]);
+					np->tx_skbuff[entry] = 0;
+					np->dirty_tx++;
+				}
+				np->tx_done_q[np->tx_done].status = 0;
+				np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1);
+			}
+			writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2);
+		}
+		if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
+			/* The ring is no longer full, clear tbusy. */
+			np->tx_full = 0;
+			clear_bit(0, (void*)&dev->tbusy);
+			mark_bh(NET_BH);
+		}
+
+		/* Abnormal error summary/uncommon events handlers. */
+		if (intr_status & IntrAbnormalSummary)
+			netdev_error(dev, intr_status);
+
+		if (--boguscnt < 0) {
+			printk(KERN_WARNING "%s: Too much work at interrupt, "
+				   "status=0x%4.4x.\n",
+				   dev->name, intr_status);
+			break;
+		}
+	} while (1);
+
+	if (debug > 4)
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+			   dev->name, readl(ioaddr + IntrStatus));
+
+#ifndef final_version
+	/* Code that should never be run!  Remove after testing.. */
+	{
+		static int stopit = 10;
+		if (dev->start == 0  &&  --stopit < 0) {
+			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
+				   dev->name);
+			free_irq(irq, dev);
+		}
+	}
+#endif
+
+#if defined(__i386__)
+	clear_bit(0, (void*)&dev->interrupt);
+#else
+	dev->interrupt = 0;
+#endif
+	return;
+}
+
+/* This routine is logically part of the interrupt handler, but seperated
+   for clarity and better register allocation. */
+static int netdev_rx(struct net_device *dev)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
+	u32 desc_status;
+	if (np->rx_done_q == 0) {
+		printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",
+			   dev->name, np->rx_done, np->tx_done_q);
+		return 0;
+	}
+
+	/* If EOP is set on the next entry, it's a new packet. Send it up. */
+	while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) {
+		if (debug > 4)
+			printk(KERN_DEBUG "  netdev_rx() status of %d was %8.8x.\n",
+				   np->rx_done, desc_status);
+		if (--boguscnt < 0)
+			break;
+		if (! (desc_status & RxOK)) {
+			/* There was a error. */
+			if (debug > 2)
+				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
+					   desc_status);
+			np->stats.rx_errors++;
+			if (desc_status & RxFIFOErr)
+				np->stats.rx_fifo_errors++;
+		} else {
+			struct sk_buff *skb;
+			u16 pkt_len = desc_status;			/* Implicitly Truncate */
+			int entry = (desc_status >> 16) & 0x7ff;
+
+#ifndef final_version
+			if (debug > 4)
+				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
+					   ", bogus_cnt %d.\n",
+					   pkt_len, boguscnt);
+#endif
+			/* Check if the packet is long enough to accept without copying
+			   to a minimally-sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+#if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
+				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+				skb_put(skb, pkt_len);
+#else
+				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
+					   pkt_len);
+#endif
+			} else {
+				char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len);
+				np->rx_skbuff[entry] = NULL;
+#ifndef final_version				/* Remove after testing. */
+				if (bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr) & ~3) != temp)
+					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+						   "do not match in netdev_rx: %p vs. %p / %p.\n",
+						   dev->name, bus_to_virt(le32_to_cpu(np->rx_ring[entry].rxaddr)),
+						   skb->head, temp);
+#endif
+			}
+#ifndef final_version				/* Remove after testing. */
+			/* You will want this info for the initial debug. */
+			if (debug > 5)
+				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
+					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
+					   "%d.%d.%d.%d.\n",
+					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],
+					   skb->data[8], skb->data[9], skb->data[10],
+					   skb->data[11], skb->data[12], skb->data[13],
+					   skb->data[14], skb->data[15], skb->data[16],
+					   skb->data[17]);
+#endif
+			skb->protocol = eth_type_trans(skb, dev);
+#ifdef full_rx_status
+			if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000)
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+#endif
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			np->stats.rx_packets++;
+		}
+		np->cur_rx++;
+		np->rx_done_q[np->rx_done].status = 0;
+		np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1);
+	}
+	writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx);
+
+	/* Refill the Rx ring buffers. */
+	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+		struct sk_buff *skb;
+		int entry = np->dirty_rx % RX_RING_SIZE;
+		if (np->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb(np->rx_buf_sz);
+			np->rx_skbuff[entry] = skb;
+			if (skb == NULL)
+				break;			/* Better luck next round. */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			np->rx_ring[entry].rxaddr = cpu_to_le32(virt_to_bus(skb->tail) | RxDescValid);
+		}
+		if (entry == RX_RING_SIZE - 1)
+			np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing);
+		/* We could defer this until later... */
+		writew(entry, dev->base_addr + RxDescQIdx);
+	}
+
+	if (debug > 5
+		|| memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1))
+		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %8.8x %d.\n",
+			   np->rx_done, desc_status,
+			   memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1));
+
+	/* Restart Rx engine if stopped. */
+	return 0;
+}
+
+static void netdev_error(struct net_device *dev, int intr_status)
+{
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+
+	if (intr_status & LinkChange) {
+		printk(KERN_ERR "%s: Link changed: Autonegotiation advertising"
+			   " %4.4x  partner %4.4x.\n", dev->name,
+			   mdio_read(dev, np->phys[0], 4),
+			   mdio_read(dev, np->phys[0], 5));
+		check_duplex(dev, 0);
+	}
+	if (intr_status & StatsMax) {
+		get_stats(dev);
+	}
+	/* Came close to underrunning the Tx FIFO, increase threshold. */
+	if (intr_status & IntrTxDataLow)
+		writel(++np->tx_threshold, dev->base_addr + TxThreshold);
+	if ((intr_status &
+		 ~(IntrAbnormalSummary|LinkChange|StatsMax|IntrTxDataLow|1)) && debug)
+		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
+			   dev->name, intr_status);
+	/* Hmmmmm, it's not clear how to recover from PCI faults. */
+	if (intr_status & IntrTxPCIErr)
+		np->stats.tx_fifo_errors++;
+	if (intr_status & IntrRxPCIErr)
+		np->stats.rx_fifo_errors++;
+}
+
+static struct enet_statistics *get_stats(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+
+	/* We should lock this segment of code for SMP eventually, although
+	   the vulnerability window is very small and statistics are
+	   non-critical. */
+#if LINUX_VERSION_CODE > 0x20119
+	np->stats.tx_bytes = readl(ioaddr + 0x57010);
+	np->stats.rx_bytes = readl(ioaddr + 0x57044);
+#endif
+	np->stats.tx_packets = readl(ioaddr + 0x57000);
+	np->stats.tx_aborted_errors =
+		readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
+	np->stats.tx_window_errors = readl(ioaddr + 0x57018);
+	np->stats.collisions = readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
+
+	/* The chip only need report frame silently dropped. */
+	np->stats.rx_dropped	   += readw(ioaddr + RxDMAStatus);
+	writew(0, ioaddr + RxDMAStatus);
+	np->stats.rx_crc_errors	   = readl(ioaddr + 0x5703C);
+	np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
+	np->stats.rx_length_errors = readl(ioaddr + 0x57058);
+	np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
+
+	return &np->stats;
+}
+
+/* The little-endian AUTODIN II ethernet CRC calculations.
+   A big-endian version is also available.
+   This is slow but compact code.  Do not use this routine for bulk data,
+   use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c.
+   Chips may use the upper or lower CRC bits, and may reverse and/or invert
+   them.  Select the endian-ness that results in minimal calculations.
+*/
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	u32 rx_mode;
+	struct dev_mc_list *mclist;
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys;
+	} else if ((dev->mc_count > multicast_filter_limit)
+			   ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to match, or accept all multicasts. */
+		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys;
+	} else if (dev->mc_count <= 15) {
+		/* Use the 16 element perfect filter. */
+		long filter_addr = ioaddr + 0x56000 + 1*16;
+		for (i = 1, mclist = dev->mc_list; mclist  &&  i <= dev->mc_count;
+			 i++, mclist = mclist->next) {
+			u16 *eaddrs = (u16 *)mclist->dmi_addr;
+			writew(*eaddrs++, filter_addr); filter_addr += 4;
+			writew(*eaddrs++, filter_addr); filter_addr += 4;
+			writew(*eaddrs++, filter_addr); filter_addr += 8;
+		}
+		while (i++ < 16) {
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 8;
+		}
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
+	} else {
+		/* Must use a multicast hash table. */
+		long filter_addr;
+		u16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));	/* Multicast hash filter */
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next) {
+			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter);
+		}
+		/* Clear the perfect filter list. */
+		filter_addr = ioaddr + 0x56000 + 1*16;
+		for (i = 1; i < 16; i++) {
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 8;
+		}
+		for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++)
+			writew(mc_filter[i], filter_addr);
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	}
+	writel(rx_mode|AcceptAll, ioaddr + RxFilterMode);
+}
+
+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	u16 *data = (u16 *)&rq->ifr_data;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
+		/* Fall Through */
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int netdev_close(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
+	int i;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (debug > 1) {
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was Int %4.4x.\n",
+			   dev->name, readl(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+	}
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	writel(0, ioaddr + IntrEnable);
+
+	/* Stop the chip's Tx and Rx processes. */
+
+	del_timer(&np->timer);
+
+#ifdef __i386__
+	if (debug > 2) {
+		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+			   (int)virt_to_bus(np->tx_ring));
+		for (i = 0; i < 8 /* TX_RING_SIZE */; i++)
+			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
+				   i, le32_to_cpu(np->tx_ring[i].status),
+				   le32_to_cpu(np->tx_ring[i].addr),
+				   le32_to_cpu(np->tx_done_q[i].status));
+		printk(KERN_DEBUG "  Rx ring at %8.8x -> %p:\n",
+			   (int)virt_to_bus(np->rx_ring), np->rx_done_q);
+		if (np->rx_done_q)
+			for (i = 0; i < 8 /* RX_RING_SIZE */; i++) {
+				printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n",
+					   i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));
+		}
+	}
+#endif /* __i386__ debugging only */
+
+	free_irq(dev->irq, dev);
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (np->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+			np->rx_skbuff[i]->free = 1;
+#endif
+			dev_kfree_skb(np->rx_skbuff[i]);
+		}
+		np->rx_skbuff[i] = 0;
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (np->tx_skbuff[i])
+			dev_kfree_skb(np->tx_skbuff[i]);
+		np->tx_skbuff[i] = 0;
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+#ifdef MODULE
+int init_module(void)
+{
+	if (debug)					/* Emit version even if no cards detected. */
+		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+#ifdef CARDBUS
+	register_driver(&etherdev_ops);
+	return 0;
+#else
+	if (pci_etherdev_probe(NULL, pci_tbl)) {
+		printk(KERN_INFO " No Starfire adapters detected, driver not loaded.\n");
+		return -ENODEV;
+	}
+	return 0;
+#endif
+}
+
+void cleanup_module(void)
+{
+	struct net_device *next_dev;
+
+#ifdef CARDBUS
+	unregister_driver(&etherdev_ops);
+#endif
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_net_dev) {
+		struct netdev_private *np =
+			(struct netdev_private *)root_net_dev->priv;
+		next_dev = np->next_module;
+		unregister_netdev(root_net_dev);
+		iounmap((char *)root_net_dev->base_addr);
+		if (np->tx_done_q) free_page((long)np->tx_done_q);
+		if (np->rx_done_q) free_page((long)np->rx_done_q);
+		kfree(root_net_dev);
+		root_net_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c starfire.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  simple-compile-command: "gcc -DMODULE -D__KERNEL__ -O6 -c starfire.c"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.3.17/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.3.17/linux/drivers/net/sun3lance.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/net/sun3lance.c	Wed Sep  8 11:20:42 1999
@@ -240,7 +240,7 @@
 
 /************************* End of Prototypes **************************/
 
-__initfunc(int sun3lance_probe( struct net_device *dev ))
+int __init sun3lance_probe( struct net_device *dev )
 {	
 	static int found = 0;
 
@@ -255,7 +255,7 @@
 	return( ENODEV );
 }
 
-__initfunc(static int lance_probe( struct net_device *dev))
+static int __init lance_probe( struct net_device *dev)
 {	
 	unsigned long ioaddr, iopte;
 	
diff -u --recursive --new-file v2.3.17/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.3.17/linux/drivers/net/sunhme.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/sunhme.c	Wed Sep  8 11:14:32 1999
@@ -2426,17 +2426,46 @@
 	int i;
 
 	for(i = 0; i < 4; i++) {
-		struct net_device *hdev = qp->happy_meals[i];
-		struct happy_meal *hp = (struct happy_meal *) hdev->priv;
-		volatile u32 *sreg = qp->irq_status[i];
-
-		if(sreg &&
-		   (hme_read32(hp, sreg) & (GREG_STAT_ERRORS |
-					    GREG_STAT_MIFIRQ |
-					    GREG_STAT_TXALL  |
-					    GREG_STAT_RXTOHOST)) != 0)
-			qp->handler(irq, hdev, ptregs);
+		struct net_device *dev = qp->happy_meals[i];
+		struct happy_meal *hp = (struct happy_meal *) dev->priv;
+		struct hmeal_gregs *gregs = hp->gregs;
+		struct hmeal_tcvregs *tregs = hp->tcvregs;
+		unsigned int happy_status = hme_read32(hp, &gregs->stat);
+
+		HMD(("quattro_interrupt: status=%08x ",happy_status));
+
+		dev->interrupt=1;
+
+		if(happy_status & GREG_STAT_ERRORS) {
+			HMD(("ERRORS "));
+			if(happy_meal_is_not_so_happy(hp, gregs, happy_status)) {
+				dev->interrupt=0;
+				break;
+			}
+		}
+
+		if(happy_status & GREG_STAT_MIFIRQ) {
+			HMD(("MIFIRQ "));
+			happy_meal_mif_interrupt(hp, gregs, tregs);
+		}
+
+		if(happy_status & GREG_STAT_TXALL) {
+			HMD(("TXALL "));
+			happy_meal_tx(hp);
+		}
+
+		if(happy_status & GREG_STAT_RXTOHOST) {
+			HMD(("RXTOHOST "));
+			happy_meal_rx(hp, dev, gregs);
+		}
+
+		if(dev->tbusy && (TX_BUFFS_AVAIL(hp) >= 0)) {
+			hp->dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+		dev->interrupt=0;
 	}
+	HMD(("done\n"));
 }
 
 static int happy_meal_open(struct net_device *dev)
@@ -2947,8 +2976,11 @@
 	struct linux_sbus_device *sdev;
 	struct quattro *qp;
 
+	if(qfe_sbus_list == NULL)
+		goto found;
+
 	for(qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-		for(sdev = qp->quattro_sbus_dev->child;
+		for(sdev = qp->quattro_sbus_dev;
 		    sdev != NULL;
 		    sdev = sdev->next) {
 			if(sdev == goal_sdev)
@@ -2980,7 +3012,7 @@
 			qp->happy_meals[i] = NULL;
 		}
 		qp->handler = NULL;
-		qp->quattro_sbus_dev = sdev;
+		qp->quattro_sbus_dev = goal_sdev;
 #ifdef CONFIG_PCI
 		qp->quattro_pci_dev = NULL;
 #endif
@@ -3037,7 +3069,7 @@
 #ifndef __sparc_v9__
 		if(sparc_cpu_model == sun4c)
 			qp->handler = sun4c_happy_meal_interrupt;
-		else if(sparc_cpu_model == sun4c)
+		else if(sparc_cpu_model == sun4d)
 			qp->handler = sun4d_happy_meal_interrupt;
 		else
 #endif
@@ -3088,7 +3120,7 @@
 		printk(version);
 
 	if(qfe_slot != -1)
-		printk("%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet",
+		printk("%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
 		       dev->name, qfe_slot);
 	else
 		printk("%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
@@ -3097,10 +3129,14 @@
 	dev->base_addr = (long) sdev;
 
 	/* XXX Check for local-mac-address property on Quattro... -DaveM */
+	/* Quattro local-mac-address... */
+	if(qfe_slot != -1 && prom_getproplen(sdev->prom_node,"local-mac-address")==6)
+		prom_getproperty(sdev->prom_node,"local-mac-address",dev->dev_addr,6);
+	else
+		memcpy(dev->dev_addr,idprom->id_ethaddr,6);
 	for(i = 0; i < 6; i++)
 		printk("%2.2x%c",
-		       dev->dev_addr[i] = idprom->id_ethaddr[i],
-		       i == 5 ? ' ' : ':');
+		       dev->dev_addr[i], i == 5 ? ' ' : ':');
 	printk("\n");
 
 	hp = (struct happy_meal *) dev->priv;
diff -u --recursive --new-file v2.3.17/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.3.17/linux/drivers/net/sunqe.c	Wed Aug 18 11:36:43 1999
+++ linux/drivers/net/sunqe.c	Fri Sep 10 11:06:19 1999
@@ -3,11 +3,11 @@
  *          controller out there can be most efficiently programmed
  *          if you make it look like a LANCE.
  *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
  */
 
 static char *version =
-        "sunqe.c:v1.1 8/Nov/96 David S. Miller (davem@caipfs.rutgers.edu)\n";
+        "sunqe.c:v2.0 9/9/99 David S. Miller (davem@redhat.com)\n";
 
 #include <linux/module.h>
 
@@ -49,6 +49,8 @@
 static struct sunqec *root_qec_dev = NULL;
 #endif
 
+static void qe_set_multicast(struct net_device *dev);
+
 #define QEC_RESET_TRIES 200
 
 static inline int qec_global_reset(struct qe_globreg *gregs)
@@ -109,82 +111,21 @@
 	return 0;
 }
 
-static inline void qe_clean_rings(struct sunqe *qep)
-{
-	int i;
-
-	for(i = 0; i < RX_RING_SIZE; i++) {
-		if(qep->rx_skbs[i] != NULL) {
-			dev_kfree_skb(qep->rx_skbs[i]);
-			qep->rx_skbs[i] = NULL;
-		}
-	}
-
-	for(i = 0; i < TX_RING_SIZE; i++) {
-		if(qep->tx_skbs[i] != NULL) {
-			dev_kfree_skb(qep->tx_skbs[i]);
-			qep->tx_skbs[i] = NULL;
-		}
-	}
-}
-
-static void qe_init_rings(struct sunqe *qep, int from_irq)
+static void qe_init_rings(struct sunqe *qep)
 {
 	struct qe_init_block *qb = qep->qe_block;
-	struct net_device *dev = qep->dev;
-	int i, gfp_flags = GFP_KERNEL;
-
-	if(from_irq || in_interrupt())
-		gfp_flags = GFP_ATOMIC;
-
-	qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0;
-
-	qe_clean_rings(qep);
-
-	for(i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb;
-
-		skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags | GFP_DMA);
-		if(!skb)
-			continue;
-
-		qep->rx_skbs[i] = skb;
-		skb->dev = dev;
-
-		skb_put(skb, ETH_FRAME_LEN);
-		skb_reserve(skb, 34);
-
-		qb->qe_rxd[i].rx_addr = sbus_dvma_addr(skb->data);
-		qb->qe_rxd[i].rx_flags =
-			(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
-	}
-
-	for(i = 0; i < TX_RING_SIZE; i++)
-		qb->qe_txd[i].tx_flags = qb->qe_txd[i].tx_addr = 0;
-}
-
-static void sun4c_qe_init_rings(struct sunqe *qep)
-{
-	struct qe_init_block *qb = qep->qe_block;
-	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
-	__u32 qbufs_dvma = qep->s4c_buf_dvma;
+	struct sunqe_buffers *qbufs = qep->buffers;
+	__u32 qbufs_dvma = qep->buffers_dvma;
 	int i;
 
 	qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0;
-
+	memset(qb, 0, sizeof(struct qe_init_block));
 	memset(qbufs, 0, sizeof(struct sunqe_buffers));
-
-	for(i = 0; i < RX_RING_SIZE; i++)
-		qb->qe_rxd[i].rx_flags = qb->qe_rxd[i].rx_addr = 0;
-
-	for(i = 0; i < SUN4C_RX_RING_SIZE; i++) {
+	for(i = 0; i < RX_RING_SIZE; i++) {
 		qb->qe_rxd[i].rx_addr = qbufs_dvma + qebuf_offset(rx_buf, i);
 		qb->qe_rxd[i].rx_flags =
-			(RXD_OWN | ((SUN4C_RX_BUFF_SIZE) & RXD_LENGTH));
+			(RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
 	}
-
-	for(i = 0; i < TX_RING_SIZE; i++)
-		qb->qe_txd[i].tx_flags = qb->qe_txd[i].tx_addr = 0;
 }
 
 static int qe_init(struct sunqe *qep, int from_irq)
@@ -205,9 +146,10 @@
 	cregs->rxds = qep->qblock_dvma + qib_offset(qe_rxd, 0);
 	cregs->txds = qep->qblock_dvma + qib_offset(qe_txd, 0);
 
-	/* Enable the various irq's. */
+	/* Enable/mask the various irq's. */
 	cregs->rimask = 0;
-	cregs->timask = 0;
+	cregs->timask = 1;
+
 	cregs->qmask = 0;
 	cregs->mmask = CREG_MMASK_RXCOLL;
 
@@ -222,6 +164,7 @@
 	cregs->pipg = 0;
 
 	/* Now dork with the AMD MACE. */
+	mregs->phyconfig = MREGS_PHYCONFIG_AUTO;
 	mregs->txfcntl = MREGS_TXFCNTL_AUTOPAD; /* Save us some tx work. */
 	mregs->rxfcntl = 0;
 
@@ -240,6 +183,8 @@
 
 	/* Tell MACE we are changing the ether address. */
 	mregs->iaconfig = (MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_PARESET);
+	while ((mregs->iaconfig & MREGS_IACONFIG_ACHNGE) != 0)
+		barrier();
 	mregs->ethaddr = e[0];
 	mregs->ethaddr = e[1];
 	mregs->ethaddr = e[2];
@@ -249,28 +194,38 @@
 
 	/* Clear out the address filter. */
 	mregs->iaconfig = (MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET);
-	for(i = 0; i < 8; i++) mregs->filter = 0;
+	while ((mregs->iaconfig & MREGS_IACONFIG_ACHNGE) != 0)
+		barrier();
+	for(i = 0; i < 8; i++)
+		mregs->filter = 0;
 
 	/* Address changes are now complete. */
 	mregs->iaconfig = 0;
 
-	if(sparc_cpu_model == sun4c)
-		sun4c_qe_init_rings(qep);
-	else
-		qe_init_rings(qep, from_irq);
+	qe_init_rings(qep);
 
 	/* Wait a little bit for the link to come up... */
+	mdelay(5);
 	if(!(mregs->phyconfig & MREGS_PHYCONFIG_LTESTDIS)) {
-		mdelay(5);
-		if(!(mregs->phyconfig & MREGS_PHYCONFIG_LSTAT))
+		int tries = 50;
+
+		while (tries--) {
+			mdelay(5);
+			barrier();
+			if((mregs->phyconfig & MREGS_PHYCONFIG_LSTAT) != 0)
+				break;
+		}
+		if (tries == 0)
 			printk("%s: Warning, link state is down.\n", qep->dev->name);
 	}
 
 	/* Missed packet counter is cleared on a read. */
 	garbage = mregs->mpcnt;
 
-	/* Turn on the MACE receiver and transmitter. */
-	mregs->mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB);
+	/* Reload multicast information, this will enable the receiver
+	 * and transmitter.  But set the base mconfig value right now.
+	 */
+	qe_set_multicast(qep->dev);
 
 	/* QEC should now start to show interrupts. */
 	return 0;
@@ -429,159 +384,27 @@
 	return mace_hwbug_workaround;
 }
 
-/* Per-QE transmit complete interrupt service routine. */
-static inline void qe_tx(struct sunqe *qep)
-{
-	struct qe_txd *txbase = &qep->qe_block->qe_txd[0];
-	struct qe_txd *this;
-	int elem = qep->tx_old;
-
-	while(elem != qep->tx_new) {
-		struct sk_buff *skb;
-
-		this = &txbase[elem];
-		if(this->tx_flags & TXD_OWN)
-			break;
-		skb = qep->tx_skbs[elem];
-		qep->tx_skbs[elem] = NULL;
-		qep->net_stats.tx_bytes+=skb->len;
-		dev_kfree_skb(skb);
-
-		qep->net_stats.tx_packets++;
-		elem = NEXT_TX(elem);
-	}
-	qep->tx_old = elem;
-}
-
-static inline void sun4c_qe_tx(struct sunqe *qep)
-{
-	struct qe_txd *txbase = &qep->qe_block->qe_txd[0];
-	struct qe_txd *this;
-	int elem = qep->tx_old;
-
-	while(elem != qep->tx_new) {
-		this = &txbase[elem];
-		if(this->tx_flags & TXD_OWN)
-			break;
-		qep->net_stats.tx_packets++;
-		elem = NEXT_TX(elem);
-	}
-	qep->tx_old = elem;
-}
-
 /* Per-QE receive interrupt service routine.  Just like on the happy meal
  * we receive directly into skb's with a small packet copy water mark.
  */
-static inline void qe_rx(struct sunqe *qep)
+static void qe_rx(struct sunqe *qep)
 {
 	struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
 	struct qe_rxd *this;
+	struct sunqe_buffers *qbufs = qep->buffers;
+	__u32 qbufs_dvma = qep->buffers_dvma;
 	int elem = qep->rx_new, drops = 0;
+	unsigned int flags;
 
 	this = &rxbase[elem];
-	while(!(this->rx_flags & RXD_OWN)) {
-		struct sk_buff *skb;
-		unsigned int flags = this->rx_flags;
-		int len = (flags & RXD_LENGTH) - 4;  /* QE adds ether FCS size to len */
-
-		/* Check for errors. */
-		if(len < ETH_ZLEN) {
-			qep->net_stats.rx_errors++;
-			qep->net_stats.rx_length_errors++;
-
-	drop_it:
-			/* Return it to the QE. */
-			qep->net_stats.rx_dropped++;
-			this->rx_addr = sbus_dvma_addr(qep->rx_skbs[elem]->data);
-			this->rx_flags =
-				(RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH));
-			goto next;
-		}
-		skb = qep->rx_skbs[elem];
-#ifdef NEED_DMA_SYNCHRONIZATION
-#ifdef __sparc_v9__
-		if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) {
-			printk("sunqe: Bogus DMA buffer address "
-			       "[%016lx]\n", ((unsigned long) skb->data));
-			panic("DMA address too large, tell DaveM");
-		}
-#endif
-		mmu_sync_dma(sbus_dvma_addr(skb->data),
-			     skb->len, qep->qe_sbusdev->my_bus);
-#endif
-		if(len > RX_COPY_THRESHOLD) {
-			struct sk_buff *new_skb;
-
-			/* Now refill the entry, if we can. */
-			new_skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, (GFP_DMA|GFP_ATOMIC));
-			if(!new_skb) {
-				drops++;
-				goto drop_it;
-			}
-
-			qep->rx_skbs[elem] = new_skb;
-			new_skb->dev = qep->dev;
-			skb_put(new_skb, ETH_FRAME_LEN);
-			skb_reserve(new_skb, 34);
-
-			rxbase[elem].rx_addr = sbus_dvma_addr(new_skb->data);
-			rxbase[elem].rx_flags =
-				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
-
-			/* Trim the original skb for the netif. */
-			skb_trim(skb, len);
-		} else {
-			struct sk_buff *copy_skb = dev_alloc_skb(len + 2);
-
-			if(!copy_skb) {
-				drops++;
-				goto drop_it;
-			}
-
-			copy_skb->dev = qep->dev;
-			skb_reserve(copy_skb, 2);
-			skb_put(copy_skb, len);
-			eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);
-
-			/* Reuse original ring buffer. */
-			rxbase[elem].rx_addr = sbus_dvma_addr(skb->data);
-			rxbase[elem].rx_flags =
-				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
-
-			skb = copy_skb;
-		}
-
-		/* No checksums are done by this card ;-( */
-		skb->protocol = eth_type_trans(skb, qep->dev);
-		netif_rx(skb);
-		qep->net_stats.rx_packets++;
-	next:
-		elem = NEXT_RX(elem);
-		this = &rxbase[elem];
-	}
-	qep->rx_new = elem;
-	if(drops)
-		printk("%s: Memory squeeze, deferring packet.\n", qep->dev->name);
-}
-
-static inline void sun4c_qe_rx(struct sunqe *qep)
-{
-	struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
-	struct qe_rxd *this;
-	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
-	__u32 qbufs_dvma = qep->s4c_buf_dvma;
-	int elem = qep->rx_new, drops = 0;
-
-	this = &rxbase[elem];
-	while(!(this->rx_flags & RXD_OWN)) {
+	while(!((flags = this->rx_flags) & RXD_OWN)) {
 		struct sk_buff *skb;
 		unsigned char *this_qbuf =
-			qbufs->rx_buf[elem & (SUN4C_RX_RING_SIZE - 1)];
+			&qbufs->rx_buf[elem & (RX_RING_SIZE - 1)][0];
 		__u32 this_qbuf_dvma = qbufs_dvma +
-			qebuf_offset(rx_buf, (elem & (SUN4C_RX_RING_SIZE - 1)));
+			qebuf_offset(rx_buf, (elem & (RX_RING_SIZE - 1)));
 		struct qe_rxd *end_rxd =
-			&rxbase[(elem+SUN4C_RX_RING_SIZE)&(RX_RING_SIZE-1)];
-		unsigned int flags = this->rx_flags;
+			&rxbase[(elem+RX_RING_SIZE)&(RX_RING_MAXSIZE-1)];
 		int len = (flags & RXD_LENGTH) - 4;  /* QE adds ether FCS size to len */
 
 		/* Check for errors. */
@@ -603,10 +426,11 @@
 				skb->protocol = eth_type_trans(skb, qep->dev);
 				netif_rx(skb);
 				qep->net_stats.rx_packets++;
+				qep->net_stats.rx_bytes+=len;
 			}
 		}
 		end_rxd->rx_addr = this_qbuf_dvma;
-		end_rxd->rx_flags = (RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH));
+		end_rxd->rx_flags = (RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
 		
 		elem = NEXT_RX(elem);
 		this = &rxbase[elem];
@@ -643,55 +467,6 @@
 
 			if(qe_status & CREG_STAT_RXIRQ)
 				qe_rx(qep);
-
-			if(qe_status & CREG_STAT_TXIRQ)
-				qe_tx(qep);
-
-			if(dev->tbusy && (TX_BUFFS_AVAIL(qep) >= 0)) {
-				dev->tbusy = 0;
-				mark_bh(NET_BH);
-			}
-
-	next:
-			dev->interrupt = 0;
-		}
-		qec_status >>= 4;
-		channel++;
-	}
-}
-
-static void sun4c_qec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct sunqec *qecp = (struct sunqec *) dev_id;
-	unsigned int qec_status;
-	int channel = 0;
-
-	/* Latch the status now. */
-	qec_status = qecp->gregs->stat;
-	while(channel < 4) {
-		if(qec_status & 0xf) {
-			struct sunqe *qep = qecp->qes[channel];
-			struct net_device *dev = qep->dev;
-			unsigned int qe_status;
-
-			dev->interrupt = 1;
-
-			qe_status = qep->qcregs->stat;
-			if(qe_status & CREG_STAT_ERRORS)
-				if(qe_is_bolixed(qep, qe_status))
-					goto next;
-
-			if(qe_status & CREG_STAT_RXIRQ)
-				sun4c_qe_rx(qep);
-
-			if(qe_status & CREG_STAT_TXIRQ)
-				sun4c_qe_tx(qep);
-
-			if(dev->tbusy && (SUN4C_TX_BUFFS_AVAIL(qep) >= 0)) {
-				dev->tbusy = 0;
-				mark_bh(NET_BH);
-			}
-
 	next:
 			dev->interrupt = 0;
 		}
@@ -705,10 +480,13 @@
 	struct sunqe *qep = (struct sunqe *) dev->priv;
 	int res;
 
+	qep->mconfig = (MREGS_MCONFIG_TXENAB |
+			MREGS_MCONFIG_RXENAB |
+			MREGS_MCONFIG_MBAENAB);
 	res = qe_init(qep, 0);
-	if(!res) {
+	if(!res)
 		MOD_INC_USE_COUNT;
-	}
+
 	return res;
 }
 
@@ -717,88 +495,66 @@
 	struct sunqe *qep = (struct sunqe *) dev->priv;
 
 	qe_stop(qep);
-	qe_clean_rings(qep);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-/* Get a packet queued to go onto the wire. */
-static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
+/* Reclaim TX'd frames from the ring. */
+static void qe_tx_reclaim(struct sunqe *qep)
 {
-	struct sunqe *qep = (struct sunqe *) dev->priv;
-	int len, entry;
-
-	if(dev->tbusy)
-		return 1;
-
-	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
-		return 1;
-	}
+	struct qe_txd *txbase = &qep->qe_block->qe_txd[0];
+	struct net_device *dev = qep->dev;
+	int elem = qep->tx_old;
 
-	if(!TX_BUFFS_AVAIL(qep))
-		return 1;
+	while(elem != qep->tx_new) {
+		unsigned int flags = txbase[elem].tx_flags;
 
-#ifdef NEED_DMA_SYNCHRONIZATION
-#ifdef __sparc_v9__
-	if ((unsigned long) (skb->data + skb->len) >= MAX_DMA_ADDRESS) {
-		struct sk_buff *new_skb = skb_copy(skb, GFP_DMA | GFP_ATOMIC);
-		if(!new_skb)
-			return 1;
-		dev_kfree_skb(skb);
-		skb = new_skb;
+		if (flags & TXD_OWN)
+			break;
+		qep->net_stats.tx_packets++;
+		qep->net_stats.tx_bytes+=(flags & TXD_LENGTH);
+		elem = NEXT_TX(elem);
 	}
-#endif
-	mmu_sync_dma(sbus_dvma_addr(skb->data),
-		     skb->len, qep->qe_sbusdev->my_bus);
-#endif
-	len = skb->len;
-	entry = qep->tx_new;
-
-	/* Avoid a race... */
-	qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE;
-
-	qep->tx_skbs[entry] = skb;
-
-	qep->qe_block->qe_txd[entry].tx_addr = sbus_dvma_addr(skb->data);
-	qep->qe_block->qe_txd[entry].tx_flags =
-		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));
-	qep->tx_new = NEXT_TX(entry);
-
-	/* Get it going. */
-	qep->qcregs->ctrl = CREG_CTRL_TWAKEUP;
+	qep->tx_old = elem;
 
-	if(TX_BUFFS_AVAIL(qep))
+	if(dev->tbusy && (TX_BUFFS_AVAIL(qep) > 0)) {
 		dev->tbusy = 0;
-
-	return 0;
+		mark_bh(NET_BH);
+	}
 }
 
-static int sun4c_qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
+/* Get a packet queued to go onto the wire. */
+static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
-	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
-	__u32 txbuf_dvma, qbufs_dvma = qep->s4c_buf_dvma;
+	struct sunqe_buffers *qbufs = qep->buffers;
+	__u32 txbuf_dvma, qbufs_dvma = qep->buffers_dvma;
 	unsigned char *txbuf;
 	int len, entry;
 
-	if(dev->tbusy)
-		return 1;
+	qe_tx_reclaim(qep);
 
 	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
+		long tickssofar = jiffies - dev->trans_start;
+
+		if (tickssofar >= 40) {
+			printk("%s: transmit timed out, resetting\n", dev->name);
+			qe_init(qep, 1);
+			dev->tbusy = 0;
+			dev->trans_start = jiffies;
+		}
 		return 1;
 	}
 
-	if(!SUN4C_TX_BUFFS_AVAIL(qep))
+	if(!TX_BUFFS_AVAIL(qep))
 		return 1;
 
 	len = skb->len;
 	entry = qep->tx_new;
 
-	txbuf = &qbufs->tx_buf[entry & (SUN4C_TX_RING_SIZE - 1)][0];
+	txbuf = &qbufs->tx_buf[entry & (TX_RING_SIZE - 1)][0];
 	txbuf_dvma = qbufs_dvma +
-		qebuf_offset(tx_buf, (entry & (SUN4C_TX_RING_SIZE - 1)));
+		qebuf_offset(tx_buf, (entry & (TX_RING_SIZE - 1)));
 
 	/* Avoid a race... */
 	qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE;
@@ -811,13 +567,12 @@
 	qep->tx_new = NEXT_TX(entry);
 
 	/* Get it going. */
+	dev->trans_start = jiffies;
 	qep->qcregs->ctrl = CREG_CTRL_TWAKEUP;
 
-	qep->net_stats.tx_bytes+=skb->len;
-	
 	dev_kfree_skb(skb);
 
-	if(SUN4C_TX_BUFFS_AVAIL(qep))
+	if(TX_BUFFS_AVAIL(qep))
 		dev->tbusy = 0;
 
 	return 0;
@@ -837,7 +592,7 @@
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
 	struct dev_mc_list *dmi = dev->mc_list;
-	unsigned char new_mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB);
+	unsigned char new_mconfig = qep->mconfig;
 	char *addrs;
 	int i, j, bit, byte;
 	u32 crc, poly = CRC_POLYNOMIAL_LE;
@@ -847,6 +602,8 @@
 
 	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
 		qep->mregs->iaconfig = MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET;
+		while ((qep->mregs->iaconfig & MREGS_IACONFIG_ACHNGE) != 0)
+			barrier();
 		for(i = 0; i < 8; i++)
 			qep->mregs->filter = 0xff;
 		qep->mregs->iaconfig = 0;
@@ -882,6 +639,8 @@
 		}
 		/* Program the qe with the new filter value. */
 		qep->mregs->iaconfig = MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET;
+		while ((qep->mregs->iaconfig & MREGS_IACONFIG_ACHNGE) != 0)
+			barrier();
 		for(i = 0; i < 8; i++)
 			qep->mregs->filter = *hbytes++;
 		qep->mregs->iaconfig = 0;
@@ -893,7 +652,8 @@
 	 * refuses to listen to anything on the network.  Sheesh, took
 	 * me a day or two to find this bug.
 	 */
-	qep->mregs->mconfig = new_mconfig;
+	qep->mconfig = new_mconfig;
+	qep->mregs->mconfig = qep->mconfig;
 
 	/* Let us get going again. */
 	dev->tbusy = 0;
@@ -904,10 +664,16 @@
 {
 	unsigned char bsizes = qecp->qec_bursts;
 
-	if(bsizes & DMA_BURST32)
+#ifdef __sparc_v9__
+	if (bsizes & DMA_BURST64) {
+		qecp->gregs->ctrl = GLOB_CTRL_B64;
+	} else
+#endif
+	if(bsizes & DMA_BURST32) {
 		qecp->gregs->ctrl = GLOB_CTRL_B32;
-	else
+	} else {
 		qecp->gregs->ctrl = GLOB_CTRL_B16;
+	}
 
 	/* Packetsize only used in 100baseT BigMAC configurations,
 	 * set it to zero just to be on the safe side.
@@ -1001,28 +767,30 @@
 	num_qranges = (i / sizeof(struct linux_prom_ranges));
 
 	/* Now, apply all the ranges, QEC ranges then the SBUS ones for each QE. */
-	for(i = 0; i < 4; i++) {
-		for(j = 0; j < 2; j++) {
-			int k;
+	if (sdev->ranges_applied == 0) {
+		for(i = 0; i < 4; i++) {
+			for(j = 0; j < 2; j++) {
+				int k;
 
-			for(k = 0; k < num_qranges; k++)
-				if(qesdevs[i]->reg_addrs[j].which_io ==
-				   qranges[k].ot_child_space)
-					break;
-			if(k >= num_qranges)
-				printk("QuadEther: Aieee, bogus QEC range for "
-				       "space %08x\n",qesdevs[i]->reg_addrs[j].which_io);
-			qesdevs[i]->reg_addrs[j].which_io = qranges[k].ot_parent_space;
-			qesdevs[i]->reg_addrs[j].phys_addr += qranges[k].ot_parent_base;
-		}
+				for(k = 0; k < num_qranges; k++)
+					if(qesdevs[i]->reg_addrs[j].which_io ==
+					   qranges[k].ot_child_space)
+						break;
+				if(k >= num_qranges)
+					printk("QuadEther: Aieee, bogus QEC range for "
+					       "space %08x\n",qesdevs[i]->reg_addrs[j].which_io);
+				qesdevs[i]->reg_addrs[j].which_io = qranges[k].ot_parent_space;
+				qesdevs[i]->reg_addrs[j].phys_addr += qranges[k].ot_parent_base;
+			}
 
-		prom_apply_sbus_ranges(qesdevs[i]->my_bus, &qesdevs[i]->reg_addrs[0],
-				       2, qesdevs[i]);
+			prom_apply_sbus_ranges(qesdevs[i]->my_bus, &qesdevs[i]->reg_addrs[0],
+					       2, qesdevs[i]);
+		}
+		prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0],
+				       sdev->num_registers, sdev);
 	}
 
 	/* Now map in the registers, QEC globals first. */
-	prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0],
-			       sdev->num_registers, sdev);
 	qecp->gregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
 				     sizeof(struct qe_globreg),
 				     "QEC Global Registers",
@@ -1093,13 +861,10 @@
 			sparc_dvma_malloc(PAGE_SIZE, "QE Init Block",
 					  &qeps[i]->qblock_dvma);
 
-		if(sparc_cpu_model == sun4c)
-			qeps[i]->sun4c_buffers = (struct sunqe_buffers *)
-				sparc_dvma_malloc(sizeof(struct sunqe_buffers),
-						  "QE RX/TX Buffers",
-						  &qeps[i]->s4c_buf_dvma);
-		else
-			qeps[i]->sun4c_buffers = 0;
+		qeps[i]->buffers = (struct sunqe_buffers *)
+			sparc_dvma_malloc(sizeof(struct sunqe_buffers),
+					  "QE RX/TX Buffers",
+					  &qeps[i]->buffers_dvma);
 
 		/* Stop this QE. */
 		qe_stop(qeps[i]);
@@ -1108,10 +873,7 @@
 	for(i = 0; i < 4; i++) {
 		qe_devs[i]->open = qe_open;
 		qe_devs[i]->stop = qe_close;
-		if(sparc_cpu_model == sun4c)
-			qe_devs[i]->hard_start_xmit = sun4c_qe_start_xmit;
-		else
-			qe_devs[i]->hard_start_xmit = qe_start_xmit;
+		qe_devs[i]->hard_start_xmit = qe_start_xmit;
 		qe_devs[i]->get_stats = qe_get_stats;
 		qe_devs[i]->set_multicast_list = qe_set_multicast;
 		qe_devs[i]->irq = sdev->irqs[0];
@@ -1119,25 +881,16 @@
 		ether_setup(qe_devs[i]);
 	}
 
-	/* QEC receives interrupts from each QE, then it send the actual
+	/* QEC receives interrupts from each QE, then it sends the actual
 	 * IRQ to the cpu itself.  Since QEC is the single point of
 	 * interrupt for all QE channels we register the IRQ handler
 	 * for it now.
 	 */
-	if(sparc_cpu_model == sun4c) {
-		if(request_irq(sdev->irqs[0], &sun4c_qec_interrupt,
-			       SA_SHIRQ, "QuadEther", (void *) qecp)) {
-			printk("QuadEther: Can't register QEC master irq handler.\n");
-			res = EAGAIN;
-			goto qec_free_devs;
-		}
-	} else {
-		if(request_irq(sdev->irqs[0], &qec_interrupt,
-			       SA_SHIRQ, "QuadEther", (void *) qecp)) {
-			printk("QuadEther: Can't register QEC master irq handler.\n");
-			res = EAGAIN;
-			goto qec_free_devs;
-		}
+	if(request_irq(sdev->irqs[0], &qec_interrupt,
+		       SA_SHIRQ, "QuadEther", (void *) qecp)) {
+		printk("QuadEther: Can't register QEC master irq handler.\n");
+		res = EAGAIN;
+		goto qec_free_devs;
 	}
 
 	/* Report the QE channels. */
@@ -1232,9 +985,12 @@
 		/* Release all four QE channels, then the QEC itself. */
 		for(i = 0; i < 4; i++) {
 			unregister_netdev(root_qec_dev->qes[i]->dev);
-			kfree(root_qec_dev->qes[i]);
+			sparc_free_io(root_qec_dev->qes[i]->qcregs, sizeof(struct qe_creg));
+			sparc_free_io(root_qec_dev->qes[i]->mregs, sizeof(struct qe_mregs));
+			kfree(root_qec_dev->qes[i]->dev);
 		}
 		free_irq(root_qec_dev->qec_sbus_dev->irqs[0], (void *)root_qec_dev);
+		sparc_free_io(root_qec_dev->gregs, sizeof(struct qe_globreg));
 		kfree(root_qec_dev);
 		root_qec_dev = next_qec;
 	}
diff -u --recursive --new-file v2.3.17/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h
--- v2.3.17/linux/drivers/net/sunqe.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/sunqe.h	Fri Sep 10 11:06:19 1999
@@ -289,29 +289,19 @@
 #define TX_RING_MAXSIZE   256
 #define RX_RING_MAXSIZE   256
 
-#define TX_RING_SIZE      256
-#define RX_RING_SIZE      256
+#define TX_RING_SIZE      16
+#define RX_RING_SIZE      16
 
-#define NEXT_RX(num)       (((num) + 1) & (RX_RING_SIZE - 1))
-#define NEXT_TX(num)       (((num) + 1) & (TX_RING_SIZE - 1))
-#define PREV_RX(num)       (((num) - 1) & (RX_RING_SIZE - 1))
-#define PREV_TX(num)       (((num) - 1) & (TX_RING_SIZE - 1))
+#define NEXT_RX(num)       (((num) + 1) & (RX_RING_MAXSIZE - 1))
+#define NEXT_TX(num)       (((num) + 1) & (TX_RING_MAXSIZE - 1))
+#define PREV_RX(num)       (((num) - 1) & (RX_RING_MAXSIZE - 1))
+#define PREV_TX(num)       (((num) - 1) & (TX_RING_MAXSIZE - 1))
 
 #define TX_BUFFS_AVAIL(qp)                                    \
         (((qp)->tx_old <= (qp)->tx_new) ?                     \
 	  (qp)->tx_old + (TX_RING_SIZE - 1) - (qp)->tx_new :  \
 			    (qp)->tx_old - (qp)->tx_new - 1)
 
-
-#define SUN4C_TX_BUFFS_AVAIL(qp)                                    \
-        (((qp)->tx_old <= (qp)->tx_new) ?                           \
-	  (qp)->tx_old + (SUN4C_TX_RING_SIZE - 1) - (qp)->tx_new :  \
-	  (qp)->tx_old - (qp)->tx_new - (TX_RING_SIZE - SUN4C_TX_RING_SIZE))
-
-
-#define RX_COPY_THRESHOLD  256
-#define RX_BUF_ALLOC_SIZE  (1546 + 64)
-
 struct qe_init_block {
 	struct qe_rxd qe_rxd[RX_RING_MAXSIZE];
 	struct qe_txd qe_txd[TX_RING_MAXSIZE];
@@ -324,72 +314,39 @@
 
 struct sunqec {
 	struct qe_globreg         *gregs;             /* QEC Global Registers         */
-
-	struct sunqe              *qes[4];
-	unsigned int               qec_bursts;
-	struct linux_sbus_device  *qec_sbus_dev;
-	struct sunqec             *next_module;
+	struct sunqe              *qes[4];	      /* Each child MACE              */
+	unsigned int               qec_bursts;	      /* Support burst sizes          */
+	struct linux_sbus_device  *qec_sbus_dev;      /* QEC's SBUS device            */
+	struct sunqec             *next_module;	      /* List of all QECs in system   */
 };
 
-#define SUN4C_PKT_BUF_SZ	1544
-#define SUN4C_RX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
-#define SUN4C_TX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
-
-#define SUN4C_RX_RING_SIZE	16
-#define SUN4C_TX_RING_SIZE	16
+#define PKT_BUF_SZ	1664
+#define RXD_PKT_SZ	1664
 
 struct sunqe_buffers {
-	char	tx_buf[SUN4C_TX_RING_SIZE][SUN4C_TX_BUFF_SIZE];
-	char	pad[2];		/* Align rx_buf for copy_and_sum(). */
-	char	rx_buf[SUN4C_RX_RING_SIZE][SUN4C_RX_BUFF_SIZE];
+	char	tx_buf[TX_RING_SIZE][PKT_BUF_SZ];
+	char	__pad[2];
+	char	rx_buf[RX_RING_SIZE][PKT_BUF_SZ];
 };
 
 #define qebuf_offset(mem, elem) \
 ((__u32)((unsigned long)(&(((struct sunqe_buffers *)0)->mem[elem][0]))))
 
-#define SUN4C_NEXT_RX(num)	(((num) + 1) & (SUN4C_RX_RING_SIZE - 1))
-#define SUN4C_NEXT_TX(num)	(((num) + 1) & (SUN4C_TX_RING_SIZE - 1))
-#define SUN4C_PREV_RX(num)	(((num) - 1) & (SUN4C_RX_RING_SIZE - 1))
-#define SUN4C_PREV_TX(num)	(((num) - 1) & (SUN4C_TX_RING_SIZE - 1))
-
 struct sunqe {
 	struct qe_creg            *qcregs;           /* QEC per-channel Registers      */
 	struct qe_mregs           *mregs;            /* Per-channel MACE Registers     */
 	struct qe_init_block      *qe_block;         /* RX and TX descriptors          */
 	__u32                      qblock_dvma;      /* RX and TX descriptors          */
-
-	struct sk_buff            *rx_skbs[RX_RING_SIZE];
-	struct sk_buff            *tx_skbs[TX_RING_SIZE];
-
-	int                        rx_new, tx_new, rx_old, tx_old;
-
-	struct sunqe_buffers      *sun4c_buffers; /* CPU visible address.  */
-	__u32                      s4c_buf_dvma;  /* DVMA visible address. */
-
+	int                        rx_new, rx_old;   /* RX ring extents		       */
+	int			   tx_new, tx_old;   /* TX ring extents		       */
+	struct sunqe_buffers      *buffers;	     /* CPU visible address.           */
+	__u32                      buffers_dvma;     /* DVMA visible address.          */
 	struct sunqec             *parent;
-
-	struct net_device_stats   net_stats;     /* Statistical counters               */
-	struct linux_sbus_device  *qe_sbusdev;   /* QE's SBUS device struct            */
-	struct net_device             *dev;          /* QE's netdevice struct              */
-	int                        channel;      /* Who am I?                          */
+	unsigned char		   mconfig;	     /* Base MACE mconfig value        */
+	struct net_device_stats    net_stats;        /* Statistical counters           */
+	struct linux_sbus_device  *qe_sbusdev;       /* QE's SBUS device struct        */
+	struct net_device         *dev;              /* QE's netdevice struct          */
+	int                        channel;          /* Who am I?                      */
 };
-
-/* We use this to acquire receive skb's that we can DMA directly into. */
-#define ALIGNED_RX_SKB_ADDR(addr) \
-        ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr))
-
-static inline struct sk_buff *qe_alloc_skb(unsigned int length, int gfp_flags)
-{
-	struct sk_buff *skb;
-
-	skb = alloc_skb(length + 64, gfp_flags);
-	if(skb) {
-		int offset = ALIGNED_RX_SKB_ADDR(skb->data);
-
-		if(offset)
-			skb_reserve(skb, offset);
-	}
-	return skb;
-}
 
 #endif /* !(_SUNQE_H) */
diff -u --recursive --new-file v2.3.17/linux/drivers/net/z85230.c linux/drivers/net/z85230.c
--- v2.3.17/linux/drivers/net/z85230.c	Wed Aug 18 11:36:43 1999
+++ linux/drivers/net/z85230.c	Wed Sep  8 11:51:22 1999
@@ -46,7 +46,7 @@
 #include <asm/io.h>
 #define RT_LOCK
 #define RT_UNLOCK
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include "z85230.h"
 #include "syncppp.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/parport/init.c linux/drivers/parport/init.c
--- v2.3.17/linux/drivers/parport/init.c	Tue Aug  3 15:24:27 1999
+++ linux/drivers/parport/init.c	Wed Sep  8 11:14:32 1999
@@ -25,6 +25,7 @@
 static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
 
 extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
+extern int parport_sunbpp_init(void);
 
 static int parport_setup_ptr __initdata = 0;
 
@@ -152,10 +153,11 @@
 #ifdef CONFIG_PARPORT_ARC
 	parport_arc_init();
 #endif
+#ifdef CONFIG_PARPORT_SUNBPP
+	parport_sunbpp_init();
+#endif
 	return 0;
 }
-
-__initcall (parport_init);
 
 #endif
 
diff -u --recursive --new-file v2.3.17/linux/drivers/parport/parport_sunbpp.c linux/drivers/parport/parport_sunbpp.c
--- v2.3.17/linux/drivers/parport/parport_sunbpp.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/parport/parport_sunbpp.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: parport_sunbpp.c,v 1.6 1999/08/31 06:57:22 davem Exp $
+/* $Id: parport_sunbpp.c,v 1.7 1999/09/02 11:59:31 davem Exp $
  * Parallel-port routines for Sun architecture
  * 
  * Author: Derrick J. Brashear <shadow@dementia.org>
@@ -49,24 +49,21 @@
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
-void
-parport_sunbpp_disable_irq(struct parport *p)
+static void parport_sunbpp_disable_irq(struct parport *p)
 {
 	struct bpp_regs *regs = (struct bpp_regs *)p->base;
 
 	regs->p_csr &= ~(DMA_INT_ENAB);
 }
 
-void
-parport_sunbpp_enable_irq(struct parport *p)
+static void parport_sunbpp_enable_irq(struct parport *p)
 {
 	struct bpp_regs *regs = (struct bpp_regs *)p->base;
 
 	regs->p_csr |= DMA_INT_ENAB;
 }
 
-void
-parport_sunbpp_write_data(struct parport *p, unsigned char d)
+static void parport_sunbpp_write_data(struct parport *p, unsigned char d)
 {
 	struct bpp_regs *regs = (struct bpp_regs *)p->base;
 
@@ -74,182 +71,183 @@
 	dprintk(("wrote 0x%x\n", d));
 }
 
-unsigned char
-parport_sunbpp_read_data(struct parport *p)
+static unsigned char parport_sunbpp_read_data(struct parport *p)
 {
 	struct bpp_regs *regs = (struct bpp_regs *)p->base;
 
 	return regs->p_dr;
 }
 
-static void
-control_pc_to_sunbpp(struct parport *p, unsigned char status)
+static void control_pc_to_sunbpp(struct parport *p, unsigned char status)
 {
-  struct bpp_regs *regs = (struct bpp_regs *)p->base;
-  unsigned char value_tcr = regs->p_tcr;
-  unsigned char value_or = regs->p_or;
+	struct bpp_regs *regs = (struct bpp_regs *)p->base;
+	unsigned char value_tcr = regs->p_tcr;
+	unsigned char value_or = regs->p_or;
 
-  if (status & PARPORT_CONTROL_STROBE) 
-    value_tcr |= P_TCR_DS;
-  if (status & PARPORT_CONTROL_AUTOFD) 
-    value_or |= P_OR_AFXN;
-  if (status & PARPORT_CONTROL_INIT) 
-    value_or |= P_OR_INIT;
-  if (status & PARPORT_CONTROL_SELECT) 
-    value_or |= P_OR_SLCT_IN;
+	if (status & PARPORT_CONTROL_STROBE) 
+		value_tcr |= P_TCR_DS;
+	if (status & PARPORT_CONTROL_AUTOFD) 
+		value_or |= P_OR_AFXN;
+	if (status & PARPORT_CONTROL_INIT) 
+		value_or |= P_OR_INIT;
+	if (status & PARPORT_CONTROL_SELECT) 
+		value_or |= P_OR_SLCT_IN;
 
-  regs->p_or = value_or;
-  regs->p_tcr = value_tcr;
+	regs->p_or = value_or;
+	regs->p_tcr = value_tcr;
 }
 
-static unsigned char 
-status_sunbpp_to_pc(struct parport *p)
+static unsigned char status_sunbpp_to_pc(struct parport *p)
 {
-  struct bpp_regs *regs = (struct bpp_regs *)p->base;
-  unsigned char bits = 0;
-  unsigned char value_tcr = regs->p_tcr;
-  unsigned char value_ir = regs->p_ir;
-
-  if (!(value_ir & P_IR_ERR))          bits |= PARPORT_STATUS_ERROR;
-  if (!(value_ir & P_IR_SLCT))      bits |= PARPORT_STATUS_SELECT;
-  if (!(value_ir & P_IR_PE))        bits |= PARPORT_STATUS_PAPEROUT;
-  if (value_tcr & P_TCR_ACK)        bits |= PARPORT_STATUS_ACK;
-  if (!(value_tcr & P_TCR_BUSY))       bits |= PARPORT_STATUS_BUSY;
-
-  dprintk(("tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir));
-  dprintk(("read status 0x%x\n", bits));
-  return bits;
+	struct bpp_regs *regs = (struct bpp_regs *)p->base;
+	unsigned char bits = 0;
+	unsigned char value_tcr = regs->p_tcr;
+	unsigned char value_ir = regs->p_ir;
+
+	if (!(value_ir & P_IR_ERR))
+		bits |= PARPORT_STATUS_ERROR;
+	if (!(value_ir & P_IR_SLCT))
+		bits |= PARPORT_STATUS_SELECT;
+	if (!(value_ir & P_IR_PE))
+		bits |= PARPORT_STATUS_PAPEROUT;
+	if (value_tcr & P_TCR_ACK)
+		bits |= PARPORT_STATUS_ACK;
+	if (!(value_tcr & P_TCR_BUSY))
+		bits |= PARPORT_STATUS_BUSY;
+
+	dprintk(("tcr 0x%x ir 0x%x\n", regs->p_tcr, regs->p_ir));
+	dprintk(("read status 0x%x\n", bits));
+	return bits;
 }
 
-static unsigned char 
-control_sunbpp_to_pc(struct parport *p)
+static unsigned char control_sunbpp_to_pc(struct parport *p)
 {
-  struct bpp_regs *regs = (struct bpp_regs *)p->base;
-  unsigned char bits = 0;
-  unsigned char value_tcr = regs->p_tcr;
-  unsigned char value_or = regs->p_or;
+	struct bpp_regs *regs = (struct bpp_regs *)p->base;
+	unsigned char bits = 0;
+	unsigned char value_tcr = regs->p_tcr;
+	unsigned char value_or = regs->p_or;
 
-  if (!(value_tcr & P_TCR_DS))      bits |= PARPORT_CONTROL_STROBE;
-  if (!(value_or & P_OR_AFXN))      bits |= PARPORT_CONTROL_AUTOFD;
-  if (!(value_or & P_OR_INIT))      bits |= PARPORT_CONTROL_INIT;
-  if (value_or & P_OR_SLCT_IN)      bits |= PARPORT_CONTROL_SELECT;
+	if (!(value_tcr & P_TCR_DS))
+		bits |= PARPORT_CONTROL_STROBE;
+	if (!(value_or & P_OR_AFXN))
+		bits |= PARPORT_CONTROL_AUTOFD;
+	if (!(value_or & P_OR_INIT))
+		bits |= PARPORT_CONTROL_INIT;
+	if (value_or & P_OR_SLCT_IN)
+		bits |= PARPORT_CONTROL_SELECT;
 
-  dprintk(("tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
-  dprintk(("read control 0x%x\n", bits));
-  return bits;
+	dprintk(("tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
+	dprintk(("read control 0x%x\n", bits));
+	return bits;
 }
 
-unsigned char 
-parport_sunbpp_read_control(struct parport *p)
+static unsigned char parport_sunbpp_read_control(struct parport *p)
 {
-  return control_sunbpp_to_pc(p);
+	return control_sunbpp_to_pc(p);
 }
 
-unsigned char 
-parport_sunbpp_frob_control(struct parport *p, unsigned char mask,
-			    unsigned char val)
+static unsigned char parport_sunbpp_frob_control(struct parport *p,
+						 unsigned char mask,
+						 unsigned char val)
 {
-  struct bpp_regs *regs = (struct bpp_regs *)p->base;
-  unsigned char value_tcr = regs->p_tcr;
-  unsigned char value_or = regs->p_or;
+	struct bpp_regs *regs = (struct bpp_regs *)p->base;
+	unsigned char value_tcr = regs->p_tcr;
+	unsigned char value_or = regs->p_or;
+
+	dprintk(("frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
+	if (mask & PARPORT_CONTROL_STROBE) {
+		if (val & PARPORT_CONTROL_STROBE) {
+			value_tcr &= ~P_TCR_DS;
+		} else {
+			value_tcr |= P_TCR_DS;
+		}
+	}
+	if (mask & PARPORT_CONTROL_AUTOFD) {
+		if (val & PARPORT_CONTROL_AUTOFD) {
+			value_or &= ~P_OR_AFXN;
+		} else {
+			value_or |= P_OR_AFXN;
+		}
+	}
+	if (mask & PARPORT_CONTROL_INIT) {
+		if (val & PARPORT_CONTROL_INIT) {
+			value_or &= ~P_OR_INIT;
+		} else {
+			value_or |= P_OR_INIT;
+		}
+	}
+	if (mask & PARPORT_CONTROL_SELECT) {
+		if (val & PARPORT_CONTROL_SELECT) {
+			value_or |= P_OR_SLCT_IN;
+		} else {
+			value_or &= ~P_OR_SLCT_IN;
+		}
+	}
 
-  dprintk(("frob1: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
-  if (mask & PARPORT_CONTROL_STROBE) {
-    if (val & PARPORT_CONTROL_STROBE)
-      value_tcr &= ~P_TCR_DS;
-    else
-      value_tcr |= P_TCR_DS;
-  }
-  if (mask & PARPORT_CONTROL_AUTOFD) {
-    if (val & PARPORT_CONTROL_AUTOFD)
-      value_or &= ~P_OR_AFXN;
-    else
-      value_or |= P_OR_AFXN;
-  }
-  if (mask & PARPORT_CONTROL_INIT) {
-    if (val & PARPORT_CONTROL_INIT)
-      value_or &= ~P_OR_INIT;
-    else
-      value_or |= P_OR_INIT;
-  }
-  if (mask & PARPORT_CONTROL_SELECT) {
-    if (val & PARPORT_CONTROL_SELECT)
-      value_or |= P_OR_SLCT_IN;
-    else
-      value_or &= ~P_OR_SLCT_IN;
-  }
-  regs->p_or = value_or;
-  regs->p_tcr = value_tcr;
-  dprintk(("frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
-  return parport_sunbpp_read_control(p);
+	regs->p_or = value_or;
+	regs->p_tcr = value_tcr;
+	dprintk(("frob2: tcr 0x%x or 0x%x\n", regs->p_tcr, regs->p_or));
+	return parport_sunbpp_read_control(p);
 }
 
-void
-parport_sunbpp_write_control(struct parport *p, unsigned char d)
+static void parport_sunbpp_write_control(struct parport *p, unsigned char d)
 {
-  const unsigned char wm = (PARPORT_CONTROL_STROBE |
-			    PARPORT_CONTROL_AUTOFD |
-			    PARPORT_CONTROL_INIT |
-			    PARPORT_CONTROL_SELECT);
+	const unsigned char wm = (PARPORT_CONTROL_STROBE |
+				  PARPORT_CONTROL_AUTOFD |
+				  PARPORT_CONTROL_INIT |
+				  PARPORT_CONTROL_SELECT);
 
-  parport_sunbpp_frob_control (p, wm, d & wm);
-  return;
+	parport_sunbpp_frob_control (p, wm, d & wm);
 }
 
-unsigned char 
-parport_sunbpp_read_status(struct parport *p)
+static unsigned char parport_sunbpp_read_status(struct parport *p)
 {
-  return status_sunbpp_to_pc(p);
+	return status_sunbpp_to_pc(p);
 }
 
-void parport_sunbpp_data_forward (struct parport *p)
+static void parport_sunbpp_data_forward (struct parport *p)
 {
-  struct bpp_regs *regs = (struct bpp_regs *)p->base;
-  unsigned char value_tcr = regs->p_tcr;
+	struct bpp_regs *regs = (struct bpp_regs *)p->base;
+	unsigned char value_tcr = regs->p_tcr;
 
-  dprintk(("forward\n"));
-  value_tcr = regs->p_tcr;
-  value_tcr &= ~P_TCR_DIR;
-  regs->p_tcr = value_tcr;
+	dprintk(("forward\n"));
+	value_tcr = regs->p_tcr;
+	value_tcr &= ~P_TCR_DIR;
+	regs->p_tcr = value_tcr;
 }
 
-void parport_sunbpp_data_reverse (struct parport *p)
+static void parport_sunbpp_data_reverse (struct parport *p)
 {
-  struct bpp_regs *regs = (struct bpp_regs *)p->base;
+	struct bpp_regs *regs = (struct bpp_regs *)p->base;
 
-  dprintk(("reverse\n"));
-  regs->p_tcr |= P_TCR_DIR;
+	dprintk(("reverse\n"));
+	regs->p_tcr |= P_TCR_DIR;
 }
 
-void
-parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s)
+static void parport_sunbpp_init_state(struct pardevice *dev, struct parport_state *s)
 {
 	s->u.pc.ctr = 0xc;
 	s->u.pc.ecr = 0x0;
 }
 
-void
-parport_sunbpp_save_state(struct parport *p, struct parport_state *s)
+static void parport_sunbpp_save_state(struct parport *p, struct parport_state *s)
 {
 	s->u.pc.ctr = parport_sunbpp_read_control(p);
 }
 
-void
-parport_sunbpp_restore_state(struct parport *p, struct parport_state *s)
+static void parport_sunbpp_restore_state(struct parport *p, struct parport_state *s)
 {
 	parport_sunbpp_write_control(p, s->u.pc.ctr);
 }
 
-void
-parport_sunbpp_inc_use_count(void)
+static void parport_sunbpp_inc_use_count(void)
 {
 #ifdef MODULE
 	MOD_INC_USE_COUNT;
 #endif
 }
 
-void
-parport_sunbpp_dec_use_count(void)
+static void parport_sunbpp_dec_use_count(void)
 {
 #ifdef MODULE
 	MOD_DEC_USE_COUNT;
@@ -294,9 +292,7 @@
         parport_ieee1284_read_byte,
 };
 
-
-int
-init_one_port(struct linux_sbus_device *sdev)
+static int __init init_one_port(struct linux_sbus_device *sdev)
 {
 	struct parport *p;
 	/* at least in theory there may be a "we don't dma" case */
@@ -306,35 +302,44 @@
 	struct bpp_regs *regs;
 	unsigned char value_tcr;
 
+	dprintk(("init_one_port(%p): ranges, alloc_io, ", sdev));
 	irq = sdev->irqs[0];
 	prom_apply_sbus_ranges(sdev->my_bus, sdev->reg_addrs, 1, sdev);
 	base = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
-				 sdev->reg_addrs[0].reg_size, 
-				 "sunbpp", sdev->reg_addrs[0].which_io, 0);
+			      sdev->reg_addrs[0].reg_size, 
+			      "sunbpp", sdev->reg_addrs[0].which_io, 0);
 	size = sdev->reg_addrs[0].reg_size;
 	dma = PARPORT_DMA_NONE;
 
+	dprintk(("alloc(ppops), "));
 	ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
         if (!ops) {
-	  sparc_free_io(base, size);
-	  return 0;
+		sparc_free_io(base, size);
+		return 0;
         }
+
         memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
 
+	dprintk(("register_port, "));
 	if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) {
-	  kfree(ops);
-	  sparc_free_io(base, size);
-	  return 0;
+		kfree(ops);
+		sparc_free_io(base, size);
+		return 0;
 	}
 
+	dprintk(("init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
+		p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
 	if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
-			       0, p->name, p)) != 0) {
-	  parport_unregister_port(p);
-	  kfree(ops);
-	  sparc_free_io(base, size);
-	  return err;
-	} else
-	  parport_sunbpp_enable_irq(p);
+			       SA_SHIRQ, p->name, p)) != 0) {
+		dprintk(("ERROR %d\n", err));
+		parport_unregister_port(p);
+		kfree(ops);
+		sparc_free_io(base, size);
+		return err;
+	} else {
+		dprintk(("OK\n"));
+		parport_sunbpp_enable_irq(p);
+	}
 
 	regs = (struct bpp_regs *)p->base;
 	dprintk(("forward\n"));
diff -u --recursive --new-file v2.3.17/linux/drivers/parport/share.c linux/drivers/parport/share.c
--- v2.3.17/linux/drivers/parport/share.c	Thu Aug  5 14:23:14 1999
+++ linux/drivers/parport/share.c	Wed Sep  8 11:51:22 1999
@@ -26,7 +26,7 @@
 #include <linux/sched.h>
 #include <linux/kmod.h>
 
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/irq.h>
 
 #undef PARPORT_PARANOID
diff -u --recursive --new-file v2.3.17/linux/drivers/pci/devlist.h linux/drivers/pci/devlist.h
--- v2.3.17/linux/drivers/pci/devlist.h	Tue Aug 31 17:29:14 1999
+++ linux/drivers/pci/devlist.h	Fri Sep 10 11:12:16 1999
@@ -548,6 +548,7 @@
 ENDVENDOR()
 
 VENDOR( VIA, "VIA Technologies" )
+	DEVICE( VIA,		VIA_8501_0,	"VT 8501")
 	DEVICE( VIA,		VIA_82C505,	"VT 82C505")
 	DEVICE( VIA,		VIA_82C561,	"VT 82C561")
 	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo IDE")
@@ -571,6 +572,7 @@
 	DEVICE(	VIA,		VIA_82C686_5,	"VT 82C686 Apollo Super AC97/Audio")
 	DEVICE(	VIA,		VIA_82C686_6,	"VT 82C686 Apollo Super AC97/Modem")
 	DEVICE( VIA,		VIA_86C100A,	"VT 86C100A")
+	DEVICE( VIA,		VIA_8501_1,	"VT 8501 PCI Bridge")
 	DEVICE( VIA,		VIA_82C597_1,	"VT 82C597 Apollo VP3 AGP")
 	DEVICE( VIA,		VIA_82C598_1,	"VT 82C598 Apollo MVP3 AGP")
 ENDVENDOR()
diff -u --recursive --new-file v2.3.17/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.17/linux/drivers/pci/pci.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pci/pci.c	Wed Sep  8 12:39:08 1999
@@ -205,6 +205,35 @@
 }
 
 /*
+ * Assign new address to PCI resource.  We hope our resource information
+ * is complete.  On the PC, we don't re-assign resources unless we are
+ * forced to do so or the driver asks us to.
+ *
+ * Expects start=0, end=size-1, flags=resource type.
+ */
+int __init 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;
+
+	if (!pr)
+		return -EINVAL;
+	if (r->flags & IORESOURCE_IO) {
+		if (size > 0x100)
+			return -EFBIG;
+		if (allocate_resource(pr, r, size, 0x1000, ~0, 1024))
+			return -EBUSY;
+	} else {
+		if (allocate_resource(pr, r, size, 0x10000000, ~0, size))
+			return -EBUSY;
+	}
+	if (i < 6)
+		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4*i, r->start);
+	return 0;
+}
+
+/*
  * Translate the low bits of the PCI base
  * to the resource type
  */
diff -u --recursive --new-file v2.3.17/linux/drivers/pci/setup.c linux/drivers/pci/setup.c
--- v2.3.17/linux/drivers/pci/setup.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pci/setup.c	Wed Sep  8 12:39:08 1999
@@ -26,7 +26,6 @@
 # define DBGC(args)
 #endif
 
-
 int __init
 pci_claim_resource(struct pci_dev *dev, int resource)
 {
diff -u --recursive --new-file v2.3.17/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.3.17/linux/drivers/pcmcia/cs.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pcmcia/cs.c	Fri Sep 10 10:33:05 1999
@@ -2238,6 +2238,8 @@
 
 extern int pcmcia_ds_init(void);
 extern int pcmcia_i82365_init(void);
+extern int init_pcnet_cs(void);
+extern int init_ray_cs(void);
 
 int pcmcia_init(void)
 {
@@ -2248,7 +2250,18 @@
 	pcmcia_i82365_init();
 
 	/* Get the ball rolling.. */
-	return pcmcia_ds_init();
+	pcmcia_ds_init();
+
+#ifdef CONFIG_PCMCIA_PCNET
+	init_pcnet_cs();
+#endif
+#ifdef CONFIG_PCMCIA_3C589
+	init_3c589_cs();
+#endif
+#ifdef CONFIG_PCMCIA_RAYCS
+	init_ray_cs();
+#endif
+	return 0;
 }
 
 #endif
diff -u --recursive --new-file v2.3.17/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.3.17/linux/drivers/pcmcia/i82365.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/pcmcia/i82365.c	Wed Sep  8 11:32:01 1999
@@ -1034,34 +1034,38 @@
 static void cb_get_state(u_short s)
 {
     socket_info_t *t = &socket[s];
-    
-    pci_readb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, &t->cache);
-    pci_readb(t->bus, t->devfn, PCI_LATENCY_TIMER, &t->pci_lat);
-    pci_readb(t->bus, t->devfn, CB_LATENCY_TIMER, &t->cb_lat);
-    pci_readb(t->bus, t->devfn, CB_CARDBUS_BUS, &t->cap.cardbus);
-    pci_readb(t->bus, t->devfn, CB_SUBORD_BUS, &t->sub_bus);
-    pci_readw(t->bus, t->devfn, CB_BRIDGE_CONTROL, &t->bcr);
-    {
-	struct pci_dev *pdev = pci_find_slot(t->bus, t->devfn);
-	t->cap.pci_irq = (pdev) ? pdev->irq : 0;
-    }
+    struct pci_dev *dev = pci_find_slot(t->bus, t->devfn);
+
+    if (!dev)
+	return;
+    pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &t->cache);
+    pci_read_config_byte(dev, PCI_LATENCY_TIMER, &t->pci_lat);
+    pci_read_config_byte(dev, CB_LATENCY_TIMER, &t->cb_lat);
+    pci_read_config_byte(dev, CB_CARDBUS_BUS, &t->cap.cardbus);
+    pci_read_config_byte(dev, CB_SUBORD_BUS, &t->sub_bus);
+    pci_read_config_word(dev, CB_BRIDGE_CONTROL, &t->bcr);
+
+    t->cap.pci_irq = dev->irq;
     if (t->cap.pci_irq >= NR_IRQS) t->cap.pci_irq = 0;
 }
 
 static void cb_set_state(u_short s)
 {
     socket_info_t *t = &socket[s];
+    struct pci_dev *dev = pci_find_slot(t->bus, t->devfn);
+
     if (t->pmcs)
-	pci_writew(t->bus, t->devfn, t->pmcs, PCI_PMCS_PWR_STATE_D0);
-    pci_writel(t->bus, t->devfn, CB_LEGACY_MODE_BASE, 0);
-    pci_writel(t->bus, t->devfn, PCI_BASE_ADDRESS_0, t->cb_phys);
-    pci_writew(t->bus, t->devfn, PCI_COMMAND, CMD_DFLT);
-    pci_writeb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, t->cache);
-    pci_writeb(t->bus, t->devfn, PCI_LATENCY_TIMER, t->pci_lat);
-    pci_writeb(t->bus, t->devfn, CB_LATENCY_TIMER, t->cb_lat);
-    pci_writeb(t->bus, t->devfn, CB_CARDBUS_BUS, t->cap.cardbus);
-    pci_writeb(t->bus, t->devfn, CB_SUBORD_BUS, t->sub_bus);
-    pci_writew(t->bus, t->devfn, CB_BRIDGE_CONTROL, t->bcr);
+	pci_write_config_word(dev, t->pmcs, PCI_PMCS_PWR_STATE_D0);
+
+    pci_write_config_dword(dev, CB_LEGACY_MODE_BASE, 0);
+    pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, t->cb_phys);
+    pci_write_config_word(dev, PCI_COMMAND, CMD_DFLT);
+    pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, t->cache);
+    pci_write_config_byte(dev, PCI_LATENCY_TIMER, t->pci_lat);
+    pci_write_config_byte(dev, CB_LATENCY_TIMER, t->cb_lat);
+    pci_write_config_byte(dev, CB_CARDBUS_BUS, t->cap.cardbus);
+    pci_write_config_byte(dev, CB_SUBORD_BUS, t->sub_bus);
+    pci_write_config_word(dev, CB_BRIDGE_CONTROL, t->bcr);
 }
 
 static int cb_get_irq_mode(u_short s)
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in
--- v2.3.17/linux/drivers/sbus/char/Config.in	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/Config.in	Wed Sep  8 11:14:32 1999
@@ -12,6 +12,7 @@
   tristate 'Bidirectional parallel port support (obsolete)' CONFIG_SUN_BPP
   tristate 'Videopix Frame Grabber (EXPERIMENTAL)' CONFIG_SUN_VIDEOPIX
   tristate 'Aurora Multiboard 1600se (EXPERIMENTAL)' CONFIG_SUN_AURORA
+  tristate 'Tadpole TS102 Microcontroller support' CONFIG_TADPOLE_TS102_UCTRL
 
   # XXX Why don't we do "source drivers/char/Config.in" somewhere?
   if [ "$CONFIG_PCI" = "y" ]; then
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v2.3.17/linux/drivers/sbus/char/Makefile	Mon May 31 22:08:10 1999
+++ linux/drivers/sbus/char/Makefile	Wed Sep  8 11:14:32 1999
@@ -95,6 +95,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_TADPOLE_TS102_UCTRL),y)
+O_OBJS += uctrl.o
+else
+  ifeq ($(CONFIG_TADPOLE_TS102_UCTRL),m)
+  M_OBJS += uctrl.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 sunkbdmap.o: sunkeymap.c
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.3.17/linux/drivers/sbus/char/pcikbd.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/pcikbd.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.32 1999/08/31 06:58:11 davem Exp $
+/* $Id: pcikbd.c,v 1.35 1999/09/01 08:09:26 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.17/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c
--- v2.3.17/linux/drivers/sbus/char/rtc.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/rtc.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.17 1999/08/31 13:32:01 anton Exp $
+/* $Id: rtc.c,v 1.18 1999/08/31 18:51:36 davem Exp $
  *
  * Linux/SPARC Real Time Clock Driver
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -29,7 +29,7 @@
 /* Retrieve the current date and time from the real time clock. */
 void get_rtc_time(struct rtc_time *t)
 {
-	struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
+	unsigned long regs = mstk48t02_regs;
 	unsigned long flags;
 	u8 tmp;
 
@@ -57,7 +57,7 @@
 /* Set the current date and time inthe real time clock. */
 void set_rtc_time(struct rtc_time *t)
 {
-	struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
+	unsigned long regs = mstk48t02_regs;
 	unsigned long flags;
 	u8 tmp;
 
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.3.17/linux/drivers/sbus/char/sab82532.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/sab82532.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.34 1999/08/31 06:58:16 davem Exp $
+/* $Id: sab82532.c,v 1.35 1999/09/01 08:09:29 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2153,7 +2153,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.34 $";
+	char *revision = "$Revision: 1.35 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.3.17/linux/drivers/sbus/char/su.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/su.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.25 1999/08/31 06:58:20 davem Exp $
+/* $Id: su.c,v 1.28 1999/09/01 08:09:32 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2214,7 +2214,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.25 $";
+	char *revision = "$Revision: 1.28 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v2.3.17/linux/drivers/sbus/char/sunserial.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/sunserial.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.69 1999/08/31 06:58:29 davem Exp $
+/* $Id: sunserial.c,v 1.70 1999/09/04 20:28:17 davem Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -386,12 +386,10 @@
 	 * So be very careful not to probe for keyboards if we are on a
 	 * serial console.
 	 */
-	if (!serial_console) {
-		if (ps2kbd_probe(&memory_start) == 0)
-			return memory_start;
-		if (su_probe(&memory_start) == 0)
-			return memory_start;
-	}
+	if (!serial_console)
+		ps2kbd_probe(&memory_start);
+	if (su_probe(&memory_start) == 0)
+		return memory_start;
 #endif
 
 	if (!ret)
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c
--- v2.3.17/linux/drivers/sbus/char/uctrl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sbus/char/uctrl.c	Wed Sep  8 11:14:32 1999
@@ -0,0 +1,155 @@
+/* $Id: uctrl.c,v 1.2 1999/09/07 23:11:08 shadow Exp $
+ * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
+ *
+ * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/sbus.h>
+
+#define UCTRL_MINOR	174
+
+struct uctrl_driver {
+	volatile u32 *regs;
+	int irq;
+};
+
+static struct uctrl_driver drv;
+
+static loff_t
+uctrl_llseek(struct file *file, loff_t offset, int type)
+{
+	return -ESPIPE;
+}
+
+static int
+uctrl_ioctl(struct inode *inode, struct file *file,
+	      unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+uctrl_open(struct inode *inode, struct file *file)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int
+uctrl_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+void uctrl_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
+	printk("in uctrl_interrupt\n");
+}
+
+static struct file_operations uctrl_fops = {
+	uctrl_llseek,
+	NULL,           /* read */
+	NULL,           /* write */
+	NULL,		/* readdir */
+	NULL,		/* poll */	
+	uctrl_ioctl,
+	NULL,		/* mmap */
+	uctrl_open,
+	NULL,		/* flush */
+	uctrl_release
+};
+
+static struct miscdevice uctrl_dev = {
+	UCTRL_MINOR,
+	"uctrl",
+	&uctrl_fops
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int uctrl_init(void))
+#endif
+{
+	struct uctrl_driver *driver = &drv;
+	int len;
+	struct linux_prom_irqs tmp_irq[2];
+        unsigned int vaddr[2] = { 0, 0 };
+	int tmpnode, uctrlnode = prom_getchild(prom_root_node);
+
+	tmpnode = prom_searchsiblings(uctrlnode, "obio");
+
+	if (tmpnode)
+	  uctrlnode = prom_getchild(tmpnode);
+
+	uctrlnode = prom_searchsiblings(uctrlnode, "uctrl");
+
+	if (!uctrlnode)
+		return -ENODEV;
+
+	/* the prom mapped it for us */
+	len = prom_getproperty(uctrlnode, "address", (void *) vaddr,
+			       sizeof(vaddr));
+	driver->regs = vaddr[0];
+
+	len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq,
+			       sizeof(tmp_irq));
+	if(!driver->irq) 
+		driver->irq = tmp_irq[0].pri;
+
+	request_irq(driver->irq, uctrl_interrupt, 0, 
+		    "uctrl", driver);
+
+	enable_irq(driver->irq);
+
+	if (misc_register(&uctrl_dev)) {
+		printk("%s: unable to get misc minor %d\n",
+		       __FUNCTION__, uctrl_dev.minor);
+		disable_irq(driver->irq);
+		free_irq(driver->irq, driver);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO, "uctrl: 0x%x (irq %d)\n", driver->regs, __irq_itoa(driver->irq));
+        return 0;
+}
+
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	struct uctrl_driver *driver = &drv;
+
+	misc_deregister(&uctrl_dev);
+	if (driver->irq) {
+		disable_irq(driver->irq);
+		free_irq(driver->irq, driver);
+	}
+	if (driver->regs)
+		driver->regs = 0;
+}
+#endif
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.3.17/linux/drivers/sbus/char/zs.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/char/zs.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.44 1999/08/31 06:58:32 davem Exp $
+/* $Id: zs.c,v 1.45 1999/09/01 08:09:35 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1844,7 +1844,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.44 $";
+	char *revision = "$Revision: 1.45 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --recursive --new-file v2.3.17/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.3.17/linux/drivers/sbus/sbus.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sbus/sbus.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.79 1999/08/31 06:57:40 davem Exp $
+/* $Id: sbus.c,v 1.80 1999/09/02 05:44:33 shadow Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -208,6 +208,9 @@
 #ifdef CONFIG_SUN_AURORA
 extern int aurora_init(void);
 #endif
+#ifdef CONFIG_TADPOLE_TS102_UCTRL
+extern int ts102_uctrl_init(void);
+#endif
 
 static void __init sbus_do_child_siblings(int start_node,
 					  struct linux_sbus_device *child,
@@ -444,6 +447,9 @@
 #endif
 #ifdef CONFIG_SUN_AURORA
 	aurora_init();
+#endif
+#ifdef CONFIG_TADPOLE_TS102_UCTRL
+	ts102_uctrl_init();
 #endif
 #ifdef __sparc_v9__
 	if (sparc_cpu_model == sun4u) {
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c
--- v2.3.17/linux/drivers/scsi/53c7,8xx.c	Mon Aug  9 10:23:09 1999
+++ linux/drivers/scsi/53c7,8xx.c	Wed Sep  8 11:51:21 1999
@@ -253,7 +253,7 @@
 #include <linux/time.h>
 #include <linux/blk.h>
 #include <linux/init.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c
--- v2.3.17/linux/drivers/scsi/53c7xx.c	Sun Aug 15 11:48:32 1999
+++ linux/drivers/scsi/53c7xx.c	Wed Sep  8 11:51:21 1999
@@ -253,7 +253,7 @@
 #include <linux/ioport.h>
 #include <linux/time.h>
 #include <linux/blk.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/pgtable.h>
 
 #ifdef CONFIG_AMIGA
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c
--- v2.3.17/linux/drivers/scsi/AM53C974.c	Mon Aug  9 10:23:09 1999
+++ linux/drivers/scsi/AM53C974.c	Wed Sep  8 11:51:21 1999
@@ -8,10 +8,10 @@
 #include <linux/string.h>
 #include <linux/blk.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- v2.3.17/linux/drivers/scsi/BusLogic.c	Thu Aug 12 10:31:05 1999
+++ linux/drivers/scsi/BusLogic.c	Wed Sep  8 11:51:21 1999
@@ -43,9 +43,9 @@
 #include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/pci.h>
+#include <linux/spinlock.h>
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <asm/system.h>
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c
--- v2.3.17/linux/drivers/scsi/NCR5380.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/scsi/NCR5380.c	Wed Sep  8 11:51:22 1999
@@ -1438,7 +1438,7 @@
 
 #ifndef DONT_USE_INTR
 #include <linux/blk.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 /*
  * Function : void NCR5380_intr (int irq)
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c
--- v2.3.17/linux/drivers/scsi/NCR53c406a.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/scsi/NCR53c406a.c	Wed Sep  8 11:51:22 1999
@@ -52,7 +52,7 @@
 #include <asm/irq.h>
 
 #include <linux/blk.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c
--- v2.3.17/linux/drivers/scsi/a2091.c	Wed Aug 18 10:00:52 1999
+++ linux/drivers/scsi/a2091.c	Wed Sep  8 11:51:22 1999
@@ -12,7 +12,7 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 #include <asm/irq.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c
--- v2.3.17/linux/drivers/scsi/a3000.c	Wed Aug 18 10:00:52 1999
+++ linux/drivers/scsi/a3000.c	Wed Sep  8 11:51:22 1999
@@ -4,6 +4,7 @@
 #include <linux/sched.h>
 #include <linux/version.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -11,7 +12,6 @@
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
-#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.3.17/linux/drivers/scsi/advansys.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/advansys.c	Wed Sep  8 12:36:07 1999
@@ -1,5 +1,5 @@
-/* $Id: advansys.c,v 1.58 1999/09/03 23:02:16 bobf Exp bobf $ */
-#define ASC_VERSION "3.2F"    /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.59 1999/09/08 18:50:51 bobf Exp bobf $ */
+#define ASC_VERSION "3.2G"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -634,7 +634,11 @@
      3.2F (9/3/99):
          1. Handle new initial function code added in v2.3.16 for all
             driver versions.
-            
+
+     3.2G (9/8/99):
+         1. Fix PCI board detection in v2.3.13 and greater kernels.
+         2. Fix comiple errors in v2.3.X with debugging enabled.
+
   J. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -737,7 +741,7 @@
 #include <linux/stat.h>
 #endif /* version >= v1.3.0 */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,95)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif /* version >= 2.1.95 */
 #include "scsi.h"
 #include "hosts.h"
@@ -4711,7 +4715,7 @@
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
                     iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
 #else /* version >= v2.3.13 */ 
-                    iop = pci_devp->resource[1].start & PCI_IOADDRESS_MASK;
+                    iop = pci_devp->resource[0].start & PCI_IOADDRESS_MASK;
 #endif /* version >= v2.3.13 */ 
                     ASC_DBG2(1,
                         "advansys_detect: vendorID %X, deviceID %X\n",
@@ -10439,9 +10443,8 @@
         (unsigned) s->last_reset);
 
     printk(
-" host_wait %x, host_queue %x, hostt %x, block %x,\n",
-        (unsigned) s->host_wait, (unsigned) s->host_queue,
-        (unsigned) s->hostt, (unsigned) s->block);
+" host_queue %x, hostt %x, block %x,\n",
+        (unsigned) s->host_queue, (unsigned) s->hostt, (unsigned) s->block);
 
     printk(
 " wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n",
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.3.17/linux/drivers/scsi/aha1542.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/scsi/aha1542.c	Wed Sep  8 11:51:22 1999
@@ -33,9 +33,9 @@
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.3.17/linux/drivers/scsi/aic7xxx.c	Wed Aug  4 22:53:14 1999
+++ linux/drivers/scsi/aic7xxx.c	Wed Sep  8 11:51:22 1999
@@ -325,7 +325,7 @@
 #endif
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
-#  include <asm/spinlock.h>
+#  include <linux/spinlock.h>
 #  include <linux/smp.h>
 #  define cpuid smp_processor_id()
 #  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c
--- v2.3.17/linux/drivers/scsi/atp870u.c	Mon Jul  5 19:56:46 1999
+++ linux/drivers/scsi/atp870u.c	Wed Sep  8 11:51:22 1999
@@ -17,9 +17,9 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <linux/pci.h>
 #include <linux/blk.h>
 #include "scsi.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c
--- v2.3.17/linux/drivers/scsi/eata.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/scsi/eata.c	Wed Sep  8 11:51:22 1999
@@ -407,7 +407,7 @@
 #endif
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #define IRQ_FLAGS
 #define IRQ_LOCK
 #define IRQ_LOCK_SAVE
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v2.3.17/linux/drivers/scsi/eata_dma.c	Thu Aug  5 15:08:56 1999
+++ linux/drivers/scsi/eata_dma.c	Wed Sep  8 11:51:22 1999
@@ -80,7 +80,7 @@
 #include <asm/pgtable.h>
 #ifdef __mips__
 #include <asm/cachectl.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #include <linux/blk.h>
 #include "scsi.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c
--- v2.3.17/linux/drivers/scsi/eata_pio.c	Thu Aug  5 15:08:56 1999
+++ linux/drivers/scsi/eata_pio.c	Wed Sep  8 11:51:22 1999
@@ -56,7 +56,7 @@
 #include <linux/stat.h>
 #include <linux/config.h>	/* for CONFIG_PCI */
 #include <linux/blk.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 struct proc_dir_entry proc_scsi_eata_pio = {
     PROC_SCSI_EATA_PIO, 9, "eata_pio",
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.3.17/linux/drivers/scsi/esp.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/esp.c	Wed Sep  8 11:51:22 1999
@@ -22,6 +22,7 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -37,7 +38,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/idprom.h>
-#include <asm/spinlock.h>
 
 #define DEBUG_ESP
 /* #define DEBUG_ESP_HME */
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/fd_mcs.c linux/drivers/scsi/fd_mcs.c
--- v2.3.17/linux/drivers/scsi/fd_mcs.c	Fri Dec 18 10:12:25 1998
+++ linux/drivers/scsi/fd_mcs.c	Wed Sep  8 11:51:22 1999
@@ -89,9 +89,9 @@
 #include <linux/proc_fs.h>
 #include <linux/delay.h>
 #include <linux/mca.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v2.3.17/linux/drivers/scsi/fdomain.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/scsi/fdomain.c	Wed Sep  8 11:51:22 1999
@@ -289,7 +289,7 @@
 #include "hosts.h"
 #include "fdomain.h"
 #include <asm/system.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- v2.3.17/linux/drivers/scsi/gdth.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/scsi/gdth.c	Wed Sep  8 11:51:22 1999
@@ -191,7 +191,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #if LINUX_VERSION_CODE >= 0x02015F
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 
 #if LINUX_VERSION_CODE >= 0x010300
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c
--- v2.3.17/linux/drivers/scsi/gvp11.c	Wed Aug 18 10:00:52 1999
+++ linux/drivers/scsi/gvp11.c	Wed Sep  8 11:51:22 1999
@@ -12,7 +12,7 @@
 #include <asm/amigahw.h>
 #include <linux/zorro.h>
 #include <asm/irq.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.3.17/linux/drivers/scsi/ibmmca.c	Mon May 10 13:00:10 1999
+++ linux/drivers/scsi/ibmmca.c	Wed Sep  8 11:51:22 1999
@@ -37,7 +37,7 @@
 #include <linux/mca.h>
 #include <asm/system.h>
 #ifndef OLDKERN
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #include <asm/io.h>
 #include "sd.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h
--- v2.3.17/linux/drivers/scsi/in2000.h	Wed Aug 18 16:44:20 1999
+++ linux/drivers/scsi/in2000.h	Thu Sep  9 22:19:35 1999
@@ -387,7 +387,7 @@
 # define CLISPIN_UNLOCK(flags) restore_flags(flags)
 #else                               /* 2.1.xxx */
 # include <linux/init.h>
-# include <asm/spinlock.h>
+# include <linux/spinlock.h>
 # define in2000__INITFUNC(function) __initfunc(function)
 # define in2000__INIT __init
 # define in2000__INITDATA __initdata
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c
--- v2.3.17/linux/drivers/scsi/ini9100u.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/scsi/ini9100u.c	Wed Sep  8 11:51:22 1999
@@ -130,7 +130,7 @@
 #endif
 #include <linux/blk.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #include <linux/stat.h>
 #include <linux/config.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.3.17/linux/drivers/scsi/inia100.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/inia100.c	Wed Sep  8 11:51:22 1999
@@ -91,7 +91,7 @@
 #endif
 #include <linux/blk.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #include "sd.h"
 #include "scsi.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c
--- v2.3.17/linux/drivers/scsi/ips.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/ips.c	Wed Sep  8 11:51:22 1999
@@ -104,7 +104,7 @@
 
 #include <linux/stat.h>
 #include <linux/config.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/smp.h>
 
 /*
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/mac53c94.c linux/drivers/scsi/mac53c94.c
--- v2.3.17/linux/drivers/scsi/mac53c94.c	Fri May  8 00:22:12 1998
+++ linux/drivers/scsi/mac53c94.c	Wed Sep  8 11:51:22 1999
@@ -15,12 +15,12 @@
 #include <linux/blk.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/spinlock.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.3.17/linux/drivers/scsi/megaraid.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/scsi/megaraid.c	Wed Sep  8 11:51:22 1999
@@ -160,7 +160,7 @@
 #if LINUX_VERSION_CODE < 0x20100
 #include <linux/bios32.h>
 #else
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 
 #include <asm/io.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c
--- v2.3.17/linux/drivers/scsi/mesh.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/mesh.c	Wed Sep  8 11:51:22 1999
@@ -19,6 +19,7 @@
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
+#include <linux/spinlock.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
@@ -27,7 +28,6 @@
 #include <asm/irq.h>
 #include <asm/hydra.h>
 #include <asm/processor.h>
-#include <asm/spinlock.h>
 #include <asm/feature.h>
 
 #include "scsi.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
--- v2.3.17/linux/drivers/scsi/ncr53c8xx.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/ncr53c8xx.c	Wed Sep  8 11:51:22 1999
@@ -122,7 +122,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #include <linux/delay.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c
--- v2.3.17/linux/drivers/scsi/pci2000.c	Thu Aug  5 15:08:56 1999
+++ linux/drivers/scsi/pci2000.c	Wed Sep  8 11:51:22 1999
@@ -54,7 +54,7 @@
 #include "psi_roy.h"
 
 #if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
 #include <linux/bios32.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.3.17/linux/drivers/scsi/pci2220i.c	Thu Aug  5 15:08:56 1999
+++ linux/drivers/scsi/pci2220i.c	Wed Sep  8 11:51:22 1999
@@ -48,7 +48,7 @@
 #include "pci2220i.h"
 
 #if LINUX_VERSION_CODE >= LINUXVERSION(2,1,95)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #if LINUX_VERSION_CODE < LINUXVERSION(2,1,93)
 #include <linux/bios32.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/psi240i.c linux/drivers/scsi/psi240i.c
--- v2.3.17/linux/drivers/scsi/psi240i.c	Tue Apr 13 07:54:02 1999
+++ linux/drivers/scsi/psi240i.c	Wed Sep  8 11:51:22 1999
@@ -33,9 +33,9 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <linux/blk.h>
 #include "scsi.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c
--- v2.3.17/linux/drivers/scsi/qlogicfas.c	Thu Feb 18 16:29:30 1999
+++ linux/drivers/scsi/qlogicfas.c	Wed Sep  8 11:51:22 1999
@@ -123,9 +123,9 @@
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/unistd.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/spinlock.h>
 #include "sd.h"
 #include "hosts.h"
 #include "qlogicfas.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.3.17/linux/drivers/scsi/qlogicfc.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/qlogicfc.c	Wed Sep  8 11:51:22 1999
@@ -53,9 +53,9 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/unistd.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/spinlock.h>
 
 #include "sd.h"
 #include "hosts.h"
@@ -1885,9 +1885,8 @@
 		       pdev->device);
 		return 1;
 	}
-	if (command & PCI_COMMAND_IO && (io_base & 3) == 1)
-		io_base &= PCI_BASE_ADDRESS_IO_MASK;
-	else {
+	if (!(command & PCI_COMMAND_IO) ||
+	    !(pdev->resource[0].flags & IORESOURCE_IO)) {
 		printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id);
 		return 1;
 	}
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c
--- v2.3.17/linux/drivers/scsi/qlogicisp.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/qlogicisp.c	Wed Sep  8 11:51:22 1999
@@ -24,9 +24,9 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/unistd.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/spinlock.h>
 #include <asm/byteorder.h>
 
 #include "sd.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.3.17/linux/drivers/scsi/qlogicpti.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/qlogicpti.c	Wed Sep  8 11:51:22 1999
@@ -21,6 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 
 #include <asm/byteorder.h>
 
@@ -31,7 +32,6 @@
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/machines.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.3.17/linux/drivers/scsi/scsi.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/scsi.c	Wed Sep  8 11:51:22 1999
@@ -54,11 +54,11 @@
 #define __KERNEL_SYSCALLS__
 
 #include <linux/unistd.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
-#include <asm/spinlock.h>
 
 #include "scsi.h"
 #include "hosts.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v2.3.17/linux/drivers/scsi/seagate.c	Tue Dec 29 11:40:35 1998
+++ linux/drivers/scsi/seagate.c	Wed Sep  8 11:51:22 1999
@@ -83,7 +83,7 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.17/linux/drivers/scsi/st.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/scsi/st.c	Wed Sep  8 11:51:22 1999
@@ -27,10 +27,10 @@
 #include <linux/mtio.h>
 #include <linux/ioctl.h>
 #include <linux/fcntl.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 /* The driver prints some debugging information on the console if DEBUG
    is defined and non-zero. */
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c
--- v2.3.17/linux/drivers/scsi/sym53c416.c	Mon Jul  5 20:35:18 1999
+++ linux/drivers/scsi/sym53c416.c	Wed Sep  8 11:51:22 1999
@@ -30,10 +30,10 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <linux/blk.h>
 #include <linux/version.h>
 #include "scsi.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
--- v2.3.17/linux/drivers/scsi/sym53c8xx.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/sym53c8xx.c	Wed Sep  8 11:51:22 1999
@@ -110,7 +110,7 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #endif
 #include <linux/delay.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.3.17/linux/drivers/scsi/tmscsim.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/scsi/tmscsim.c	Wed Sep  8 11:51:22 1999
@@ -188,13 +188,13 @@
  * undef  : traditional save_flags; cli; restore_flags;
  */
 
-//#define DEBUG_SPINLOCKS 2	/* Set to 0, 1 or 2 in include/asm/spinlock.h */
+//#define DEBUG_SPINLOCKS 2	/* Set to 0, 1 or 2 in include/linux/spinlock.h */
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
 # include <linux/init.h>
-# include <asm/spinlock.h>
+# include <linux/spinlock.h>
 #endif
 
 
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c
--- v2.3.17/linux/drivers/scsi/u14-34f.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/scsi/u14-34f.c	Wed Sep  8 11:51:22 1999
@@ -359,7 +359,7 @@
 #endif
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,101)
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #define IRQ_FLAGS
 #define IRQ_LOCK
 #define IRQ_LOCK_SAVE
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v2.3.17/linux/drivers/scsi/ultrastor.c	Fri Aug  6 11:43:09 1999
+++ linux/drivers/scsi/ultrastor.c	Wed Sep  8 11:51:22 1999
@@ -134,10 +134,10 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/dma.h>
 
 #define ULTRASTOR_PRIVATE	/* Get the private stuff from ultrastor.h */
diff -u --recursive --new-file v2.3.17/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v2.3.17/linux/drivers/scsi/wd7000.c	Thu Aug  5 14:43:32 1999
+++ linux/drivers/scsi/wd7000.c	Wed Sep  8 11:51:22 1999
@@ -152,8 +152,8 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/malloc.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/sgi/char/ds1286.c linux/drivers/sgi/char/ds1286.c
--- v2.3.17/linux/drivers/sgi/char/ds1286.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sgi/char/ds1286.c	Wed Sep  8 11:59:00 1999
@@ -37,11 +37,11 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/rtc.h>
+#include <linux/spinlock.h>
 
 #include <asm/ds1286.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
 #include <asm/system.h>
 
 #define DS1286_VERSION		"1.0"
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.3.17/linux/drivers/sound/cmpci.c	Tue Sep  7 12:14:06 1999
+++ linux/drivers/sound/cmpci.c	Wed Sep  8 11:51:22 1999
@@ -77,7 +77,7 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.17/linux/drivers/sound/es1370.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/sound/es1370.c	Wed Sep  8 11:51:22 1999
@@ -149,7 +149,7 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.17/linux/drivers/sound/es1371.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/sound/es1371.c	Wed Sep  8 11:51:22 1999
@@ -105,9 +105,9 @@
 #include <linux/poll.h>
 #include <linux/bitops.h>
 #include <linux/proc_fs.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 #include "ac97.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.17/linux/drivers/sound/esssolo1.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/sound/esssolo1.c	Wed Sep  8 11:51:22 1999
@@ -78,7 +78,7 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.3.17/linux/drivers/sound/maestro.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/sound/maestro.c	Wed Sep  8 11:51:22 1999
@@ -118,7 +118,7 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/msnd.c linux/drivers/sound/msnd.c
--- v2.3.17/linux/drivers/sound/msnd.c	Thu Sep 10 16:37:26 1998
+++ linux/drivers/sound/msnd.c	Wed Sep  8 11:51:22 1999
@@ -44,7 +44,7 @@
 #  include <linux/init.h>
 #  include <asm/io.h>
 #  include <asm/uaccess.h>
-#  include <asm/spinlock.h>
+#  include <linux/spinlock.h>
 #endif
 #include <asm/irq.h>
 #include "msnd.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.17/linux/drivers/sound/sonicvibes.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/sound/sonicvibes.c	Wed Sep  8 11:51:22 1999
@@ -100,7 +100,7 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 
diff -u --recursive --new-file v2.3.17/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c
--- v2.3.17/linux/drivers/sound/vwsnd.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/sound/vwsnd.c	Wed Sep  8 11:51:22 1999
@@ -140,9 +140,9 @@
 
 #include <linux/module.h>
 #include <linux/stddef.h>
+#include <linux/spinlock.h>
 #include <asm/fixmap.h>
 #include <asm/sgi-cobalt.h>
-#include <asm/spinlock.h>
 
 #include "sound_config.h"
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.17/linux/drivers/usb/acm.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/usb/acm.c	Fri Sep 10 12:59:49 1999
@@ -56,8 +56,8 @@
 #include <linux/tty_flip.h>
 #include <linux/tty.h>
 #include <linux/module.h>
-//#include <sys/ioctl.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
+
 #include "usb.h"
 
 #define NR_PORTS 3
@@ -253,7 +253,7 @@
 static int rs_open(struct tty_struct *tty, struct file * filp) 
 {
 	struct acm_state *acm;
-
+	int ret;
 	
 	info("USB_FILE_OPEN\n");
 
@@ -272,10 +272,12 @@
 	acm->active=1;
  
 	/*Start reading from the device*/
-	acm->ctrltransfer=usb_request_irq(acm->dev,acm->ctrlpipe, acm_irq, acm->ctrlinterval, acm);
-	
+	ret = usb_request_irq(acm->dev,acm->ctrlpipe, acm_irq, acm->ctrlinterval, acm, &acm->ctrltransfer);
+	if (ret) {
+		printk (KERN_WARNING "usb-acm: usb_request_irq failed (0x%x)\n", ret);
+	}
 	acm->reading=1;
-	acm->readtransfer=usb_request_bulk(acm->dev,acm->readpipe, acm_read_irq, acm->readbuffer, acm->readsize, acm );
+	acm->readtransfer=usb_request_bulk(acm->dev,acm->readpipe, acm_read_irq, acm->readbuffer, acm->readsize, acm);
 	
 	Set_Control_Line_Status (CTRL_STAT_DTR | CTRL_STAT_RTS, acm);
 				                  
@@ -307,7 +309,7 @@
 		usb_terminate_bulk(acm->dev, acm->readtransfer);
 		acm->reading=0;
 	}
-//  usb_release_irq(acm->dev,acm->ctrltransfer);
+//  usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
 	
 	acm->active=0;
 }
@@ -591,7 +593,7 @@
 		usb_terminate_bulk(acm->dev, acm->readtransfer);
 		acm->reading=0;
 	}
-//  usb_release_irq(acm->dev,acm->ctrltransfer);
+//  usb_release_irq(acm->dev,acm->ctrltransfer, acm->ctrlpipe);
 	//BUG: What to do if a device is open?? Notify process or not allow cleanup?
 	acm->active=0;
 	acm->present=0;
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.17/linux/drivers/usb/audio.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/audio.c	Fri Sep 10 12:59:49 1999
@@ -17,6 +17,7 @@
 	struct list_head list;
 
 	void *irq_handle;
+	unsigned int irqpipe;
 };
 
 static struct usb_driver usb_audio_driver = {
@@ -90,11 +91,13 @@
 */
         
 /*
-	aud->irq_handle = usb_request_irq(dev,
-		usb_rcvctrlpipe(dev, endpoint->bEndpointAddress),
-		usb_audio_irq,
-		endpoint->bInterval,
-		aud);
+	aud->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress);
+	na = usb_request_irq(dev, aud->irqpipe,
+		usb_audio_irq, endpoint->bInterval,
+		aud, &aud->irq_handle);
+	if (na) {
+		printk (KERN_WARNING "usb-audio: usb_request_irq failed (0x%x)\n", na);
+	}
 */
 
 	list_add(&aud->list, &usb_audio_list);
@@ -111,8 +114,7 @@
 
        	list_del(&aud->list);
 
-	usb_release_irq(aud->dev, aud->irq_handle);
-	aud->irq_handle = NULL;
+	usb_release_irq(aud->dev, aud->irq_handle, aud->irqpipe);
 
        	kfree(aud);
        	dev->private = NULL;
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.17/linux/drivers/usb/cpia.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/cpia.c	Wed Sep  8 11:51:22 1999
@@ -19,8 +19,8 @@
 #include <linux/vmalloc.h>
 #include <linux/wrapper.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 
-#include <asm/spinlock.h>
 #include <asm/io.h>
 
 #include "usb.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c
--- v2.3.17/linux/drivers/usb/ezusb.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/ezusb.c	Wed Sep  8 11:51:22 1999
@@ -40,7 +40,7 @@
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
 
 #include "usb.h"
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/hp_scanner.c linux/drivers/usb/hp_scanner.c
--- v2.3.17/linux/drivers/usb/hp_scanner.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/hp_scanner.c	Wed Sep  8 11:51:22 1999
@@ -42,7 +42,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include "usb.h"
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.17/linux/drivers/usb/hub.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/hub.c	Fri Sep 10 12:59:49 1999
@@ -12,8 +12,8 @@
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
+#include <linux/spinlock.h>
 
-#include <asm/spinlock.h>
 #include <asm/uaccess.h>
 
 #include "usb.h"
@@ -191,6 +191,7 @@
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_hub *hub;
 	unsigned long flags;
+	int ret;
 
 	/* We don't handle multi-config hubs */
 	if (dev->descriptor.bNumConfigurations != 1)
@@ -248,8 +249,15 @@
 	spin_unlock_irqrestore(&hub_list_lock, flags);
 
 	if (usb_hub_configure(hub) >= 0) {
-		hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev,
-			endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
+		hub->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress);
+		ret = usb_request_irq(dev, hub->irqpipe,
+			hub_irq, endpoint->bInterval,
+			hub, &hub->irq_handle);
+		if (ret) {
+			printk (KERN_WARNING "usb-hub: usb_request_irq failed (0x%x)\n", ret);
+			/* FIXME: need to free <hub> but first clean up its list. */
+			return -1;
+		}
 
 		/* Wake up khubd */
 		wake_up(&khubd_wait);
@@ -274,8 +282,7 @@
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
 	if (hub->irq_handle) {
-		usb_release_irq(hub->dev, hub->irq_handle);
-		hub->irq_handle = NULL;
+		usb_release_irq(hub->dev, hub->irq_handle, hub->irqpipe);
 	}
 
 	/* Free the memory */
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/hub.h linux/drivers/usb/hub.h
--- v2.3.17/linux/drivers/usb/hub.h	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/hub.h	Fri Sep 10 12:59:49 1999
@@ -86,8 +86,9 @@
 	/* Device structure */
 	struct usb_device *dev;
 
-	/* Reference to the hub's polling IRQ */
+	/* Reference to the hub's polling IRQ and its associated pipe */
 	void *irq_handle;
+	unsigned int irqpipe;
 
 	/* List of hubs */
 	struct list_head hub_list;
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/keyboard.c linux/drivers/usb/keyboard.c
--- v2.3.17/linux/drivers/usb/keyboard.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/keyboard.c	Fri Sep 10 12:59:49 1999
@@ -1,3 +1,11 @@
+/*
+	Fixes:
+	1999/09/04 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+		Handle states in usb_kbd_irq
+	1999/09/06 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+		rmmod usb-keyboard doesn't crash the system anymore: the irq
+		handlers are correctly released with usb_release_irq
+*/
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
@@ -31,6 +39,8 @@
     unsigned char repeat_key;
     struct timer_list repeat_timer;
     struct list_head list;
+    unsigned int irqpipe;
+    void *irq_handler; /* host controller's IRQ transfer handle */
 };
 
 extern unsigned char usb_kbd_map[];
@@ -97,8 +107,22 @@
     struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
     unsigned long *down = (unsigned long*) buffer;
 
-    if(kbd->down[0] != down[0] || kbd->down[1] != down[1])
-    {
+    /*
+     * USB_ST_NOERROR is the normal case.
+     * USB_ST_REMOVED occurs if keyboard disconnected
+     * On other states, ignore
+     */
+
+    switch (state) {
+	case USB_ST_REMOVED:
+	case USB_ST_INTERNALERROR:
+        	printk(KERN_DEBUG "%s(%d): Suspending\n", __FILE__, __LINE__);
+		return 0; /* disable */
+	case USB_ST_NOERROR: break;
+		default: return 1; /* ignore */
+    }
+
+    if(kbd->down[0] != down[0] || kbd->down[1] != down[1]) {
         unsigned char *olddown, *newdown;
         unsigned char modsdelta, key;
         int i;
@@ -172,7 +196,8 @@
     struct usb_interface_descriptor *interface;
     struct usb_endpoint_descriptor *endpoint;
     struct usb_keyboard *kbd;
-
+    int ret;
+    
     if (dev->descriptor.bNumConfigurations < 1)
 	return -1;
 
@@ -202,11 +227,14 @@
         usb_set_protocol(dev, 0);
         usb_set_idle(dev, 0, 0);
         
-        usb_request_irq(dev,
-                        usb_rcvctrlpipe(dev, endpoint->bEndpointAddress),
-                        usb_kbd_irq,
-                        endpoint->bInterval,
-                        kbd);
+	kbd->irqpipe = usb_rcvctrlpipe(dev, endpoint->bEndpointAddress);
+	ret = usb_request_irq(dev, kbd->irqpipe,
+				usb_kbd_irq, endpoint->bInterval,
+				kbd, &kbd->irq_handler);
+	if (ret) {
+		printk(KERN_INFO "usb-keyboard failed usb_request_irq (0x%x)\n", ret);
+		goto probe_err;
+	}
 
         list_add(&kbd->list, &usb_kbd_list);
 	
@@ -223,12 +251,13 @@
 usb_kbd_disconnect(struct usb_device *dev)
 {
     struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private;
-    if(kbd)
+    if (kbd)
     {
-        dev->private = NULL;
-        list_del(&kbd->list);
-        del_timer(&kbd->repeat_timer);
-        kfree(kbd);
+	usb_release_irq(dev, kbd->irq_handler, kbd->irqpipe);
+	dev->private = NULL;
+	list_del(&kbd->list);
+	del_timer(&kbd->repeat_timer);
+	kfree(kbd);
     }
 
     printk(KERN_INFO "USB HID boot protocol keyboard removed.\n");
@@ -240,6 +269,30 @@
     return 0;
 }
 
+void usb_kbd_cleanup(void)
+{
+	struct list_head *cur, *head = &usb_kbd_list;
+
+	cur = head->next;
+
+	while (cur != head) {
+		struct usb_keyboard *kbd = list_entry(cur, struct usb_keyboard, list);
+
+		cur = cur->next;
+
+                list_del(&kbd->list);
+                INIT_LIST_HEAD(&kbd->list);
+
+		if (kbd->irq_handler) {
+			usb_release_irq(kbd->dev, kbd->irq_handler, kbd->irqpipe);
+			/* never keep a reference to a released IRQ! */
+			kbd->irq_handler = NULL;
+		}
+	}
+
+	usb_deregister(&usb_kbd_driver);
+}
+
 #ifdef MODULE
 int init_module(void)
 {
@@ -248,7 +301,7 @@
 
 void cleanup_module(void)
 {
-	usb_deregister(&usb_kbd_driver);
+	usb_kbd_cleanup();
 }
 #endif
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.3.17/linux/drivers/usb/mouse.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/mouse.c	Fri Sep 10 12:59:49 1999
@@ -40,8 +40,7 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/module.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include "usb.h"
 
@@ -149,7 +148,8 @@
 	if (--mouse->active == 0) {
 		mouse->suspended = 0;
 		/* stop polling the mouse while its not in use */
-	    	usb_release_irq(mouse->dev, mouse->irq_handle);
+	    	usb_release_irq(mouse->dev, mouse->irq_handle,
+				usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress));
 		/* never keep a reference to a released IRQ! */
 		mouse->irq_handle = NULL;
 	}
@@ -160,6 +160,7 @@
 static int open_mouse(struct inode * inode, struct file * file)
 {
 	struct mouse_state *mouse = &static_mouse_state;
+	int ret;
 
 	printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__);
 	/*
@@ -195,7 +196,13 @@
 		return 0;
 
 	/* start the usb controller's polling of the mouse */
-	mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL);
+	ret = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress),
+			mouse_irq, mouse->bInterval,
+			NULL, &mouse->irq_handle);
+	if (ret) {
+		printk (KERN_WARNING "usb-mouse: usb_request_irq failed (0x%x)\n", ret);
+		return ret;
+	}
 
 	return 0;
 }
@@ -321,6 +328,7 @@
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *endpoint;
 	struct mouse_state *mouse = &static_mouse_state;
+	int ret;
 
 	/* We don't handle multi-config mice */
 	if (dev->descriptor.bNumConfigurations != 1)
@@ -373,9 +381,13 @@
 	{
 		printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__);
 		/* restart the usb controller's polling of the mouse */
-		mouse->irq_handle = usb_request_irq(mouse->dev,
-			usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress),
-			mouse_irq, mouse->bInterval, NULL);
+		ret = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress),
+			mouse_irq, mouse->bInterval,
+			NULL, &mouse->irq_handle);
+		if (ret) {
+			printk (KERN_WARNING "usb-mouse: usb_request_irq failed (0x%x)\n", ret);
+			return ret;
+		}
 		mouse->suspended = 0;
 	}
 
@@ -388,7 +400,8 @@
 
 	/* stop the usb interrupt transfer */
 	if (mouse->present) {
-	    	usb_release_irq(mouse->dev, mouse->irq_handle);
+	    	usb_release_irq(mouse->dev, mouse->irq_handle,
+				usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress));
 		/* never keep a reference to a released IRQ! */
 	}
 
@@ -428,7 +441,8 @@
 
 	/* stop the usb interrupt transfer */
 	if (mouse->present) {
-	    	usb_release_irq(mouse->dev, mouse->irq_handle);
+	    	usb_release_irq(mouse->dev, mouse->irq_handle,
+				usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress));
 		/* never keep a reference to a released IRQ! */
 		mouse->irq_handle = NULL;
 	}
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.3.17/linux/drivers/usb/ohci-hcd.c	Wed Aug 18 16:22:23 1999
+++ linux/drivers/usb/ohci-hcd.c	Fri Sep 10 12:59:49 1999
@@ -5,7 +5,7 @@
  *
  * The OHCI HCD layer is a simple but nearly complete implementation of what 
  * the USB people would call a HCD  for the OHCI. 
- * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+ * (ISO alpha , Bulk, INT u. CTRL transfers enabled)
  * The layer on top of it, is for interfacing to the alternate-usb 
  * device-drivers.
  * 
@@ -17,12 +17,15 @@
  * [ $Log: ohci.c,v $ ]
  * [ Revision 1.1  1999/04/05 08:32:30  greg ]
  * 
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18 
  * v3.0 1999/06/25 
  * v2.1 1999/05/09  code clean up
  * v2.0 1999/05/04 
- * virtual root hub is now an option, 
+ * virtual root hub is now enabled, 
  * memory allocation based on kmalloc and kfree now, Bus error handling, 
- * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * INT, CTRL and BULK transfers enabled, ISO needs testing (alpha)
  * 
  * from Linus Torvalds (uhci.c) (APM not tested; hub, usb_device, bus and related stuff)
  * from Greg Smith (ohci.c) (reset controller handling, hub)
@@ -44,8 +47,8 @@
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
+#include <linux/spinlock.h>
 
-#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -58,8 +61,11 @@
 static int handle_apm_event(apm_event_t event);
 static int apm_resume = 0;
 #endif
+
 static int ohci_link_ed(struct ohci * ohci, struct usb_ohci_ed *ed);
- 
+static int sohci_kill_isoc (struct usb_isoc_desc *id);
+static int sohci_get_current_frame_number (struct usb_device *usb_dev);
+static int sohci_run_isoc(struct usb_isoc_desc *id, struct usb_isoc_desc *pr_id);
 static DECLARE_WAIT_QUEUE_HEAD(op_wakeup);
  
 void usb_pipe_to_hcd_ed(struct usb_device *usb_dev, unsigned int pipe, struct usb_hcd_ed  *hcd_ed) 
@@ -70,7 +76,8 @@
 	hcd_ed->type     = usb_pipetype(pipe);
 	hcd_ed->slow     = usb_pipeslow(pipe);
 	hcd_ed->maxpack  = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
-	OHCI_DEBUG(printk("******* hcd_ed: endpoint: %4x, function: %4x, out: %4x, type: %4x, slow: %4x, maxpack: %4x\n", hcd_ed->endpoint, hcd_ed->function, hcd_ed->out, hcd_ed->type, hcd_ed->slow, hcd_ed->maxpack); )
+	OHCI_DEBUG(printk("******* hcd_ed: pipe: %8x, endpoint: %4x, function: %4x, out: %4x, type: %4x, slow: %4x, maxpack: %4x\n", pipe, hcd_ed->endpoint, hcd_ed->function, hcd_ed->out, hcd_ed->type, hcd_ed->slow, hcd_ed->maxpack); )
+OHCI_DEBUG(printk("******* dev: devnum: %4x, slow: %4x, maxpacketsize: %4x\n",usb_dev->devnum, usb_dev->slow, usb_dev->maxpacketsize); )
 }
 
 
@@ -81,7 +88,10 @@
 static int sohci_blocking_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
 {  
 	if(lw0 != NULL) {
-		((struct ohci_state * )lw0)->status = status;
+		if(USB_ST_CRC < 0 && (status == USB_ST_DATAUNDERRUN || status == USB_ST_NOERROR)) 
+			((struct ohci_state * )lw0)->status = data_len;
+		else
+			((struct ohci_state * )lw0)->status = status;
 		((struct ohci_state * )lw0)->len = data_len;
 	}
 	if(lw1 != NULL) {
@@ -116,8 +126,60 @@
  
 	return 0;
 }
-                                                         
-static void * sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+
+static int sohci_iso_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1) {
+
+	// struct ohci * ohci = ohci_in; 
+	unsigned int ix = (unsigned int) lw0;
+	struct usb_isoc_desc * id = (struct usb_isoc_desc *) lw1;
+	struct usb_ohci_td **tdp = id->td;
+	int ret = 0;
+	int fx;
+
+	OHCI_DEBUG({ int i; printk("USB HC ISO |||: %x: data(%d):", ed->hwINFO, data_len);)
+	OHCI_DEBUG( for(i=0; i < 16 ; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ... ret_status: %x\n", status); })
+
+	tdp[ix] = NULL;
+	id->frames[ix].frame_length = data_len;
+	id->frames[ix].frame_status = status;
+	id->total_length += data_len;
+	if(status) id->error_count++;
+	
+	id->cur_completed_frame++;
+	id->total_completed_frames++;
+	
+	if(id->cur_completed_frame == id->callback_frames) {
+		id->prev_completed_frame = id->cur_completed_frame;
+		id->cur_completed_frame = 0;
+		OHCI_DEBUG(printk("USB HC ISO <<<: %x: \n", ed->hwINFO);)
+		ret = id->callback_fn(id->error_count, id->data, id->total_length, id);
+		switch (ret) {
+			case CB_CONT_RUN:
+				for (fx = 0; fx < id->frame_count; fx++)
+					id->frames[fx].frame_length = id->frame_size;
+				sohci_run_isoc(id, id->prev_isocdesc);
+				break;
+				
+			case CB_CONTINUE:
+				break;
+		
+			case CB_REUSE:
+				break;
+		
+			case CB_RESTART:
+				break;
+		
+			case CB_ABORT:
+				sohci_kill_isoc(id);
+				break;
+		}
+	}
+	
+	return 0;
+}
+                                                     
+static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
 {
 	struct ohci * ohci = usb_dev->bus->hcpriv;
 	struct ohci_device * dev = usb_to_ohci(usb_dev);
@@ -126,7 +188,7 @@
 
 #ifdef  VROOTHUB
 	if(usb_pipedevice(pipe) == ohci->rh.devnum) 
-		return root_hub_request_irq(usb_dev, pipe, handler, period, dev_id);
+		return root_hub_request_irq(usb_dev, pipe, handler, period, dev_id, handle);
 #endif		
 
 	usb_pipe_to_hcd_ed(usb_dev, pipe, &hcd_ed);
@@ -136,8 +198,9 @@
 	OHCI_DEBUG( printk("USB HC IRQ>>>: %x: every %d ms\n", ed->hwINFO, period);) 
 	
 	ohci_trans_req(ohci, ed, 0, NULL, dev->data, hcd_ed.maxpack, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id, INT_IN, sohci_int_handler);
-	if (ED_STATE(ed) != ED_OPER)  ohci_link_ed(ohci, ed);	
-	return ed;
+	if (ED_STATE(ed) != ED_OPER)  ohci_link_ed(ohci, ed);
+	*handle = ed;
+	return 0;
     
 }
 
@@ -146,8 +209,8 @@
 	// struct usb_device *usb_dev = ((struct ohci_device *) ((unsigned int)ed & 0xfffff000))->usb;
 	struct ohci * ohci = usb_dev->bus->hcpriv; 
 	
-	OHCI_DEBUG( printk("USB HC RM_IRQ>>>:%4x\n", (unsigned int) ed);)
-	
+	OHCI_DEBUG( printk("USB HC ***** RM_IRQ>>>:%4x\n", (unsigned int) ed);)
+
 	if(ed == NULL) return 0;
 			 
 #ifdef  VROOTHUB
@@ -157,7 +220,7 @@
 	ED_setSTATE((struct usb_ohci_ed *)ed, ED_STOP);
 	 
     usb_ohci_rm_ep(usb_dev, (struct usb_ohci_ed *) ed, NULL, NULL, NULL, 0);
-     
+ 
 	return 0;
 }
 
@@ -179,7 +242,7 @@
  	
 	ed = usb_ohci_add_ep(usb_dev, &hcd_ed, 0, 1);
 	
- 	OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: %x: ctrl(%d):", ed->hwINFO, 8);)
+ 	OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: ed:%x-%x: ctrl(%d):", (unsigned int) ed, ed->hwINFO, 8);)
 	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) cmd)[i]);)
 	OHCI_DEBUG( printk(" data(%d):", len);) 
 	OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
@@ -191,7 +254,7 @@
     OHCI_DEBUG(printk("USB HC trans req ed %x: %x :", ed->hwINFO, (unsigned int ) ed); )
  	OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; )
  	if (ED_STATE(ed) != ED_OPER)  ohci_link_ed(ohci, ed);
- 	schedule_timeout(HZ/10);
+ 	schedule_timeout(HZ*5);
    
     if(state.status == TD_NOTACCESSED) {	
     	current->state = TASK_UNINTERRUPTIBLE;
@@ -223,7 +286,7 @@
 	ohci_trans_req(ohci, ed, 0, NULL, data, len, (__OHCI_BAG) &state, (__OHCI_BAG) &wait,(usb_pipeout(pipe))?BULK_OUT:BULK_IN, sohci_blocking_handler);
 	if (ED_STATE(ed) != ED_OPER)  ohci_link_ed(ohci, ed);
 	
-	schedule_timeout(HZ/10);
+	schedule_timeout(HZ*5);
 
 	if(state.status == TD_NOTACCESSED) {		
     	current->state = TASK_UNINTERRUPTIBLE;
@@ -267,13 +330,36 @@
 	return 1;
 }
 
-static int sohci_usb_deallocate(struct usb_device *usb_dev) {
+static int sohci_alloc_dev(struct usb_device *usb_dev)
+{
+	struct ohci_device *dev;
+
+	/* Allocate the OHCI_HCD device private data */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -1;
+
+	/* Initialize "dev" */
+	memset(dev, 0, sizeof(*dev));
+
+	usb_dev->hcpriv = dev;
+	dev->usb = usb_dev;
+	atomic_set(&dev->refcnt, 1);
+
+	if (usb_dev->parent)
+		dev->ohci = usb_to_ohci(usb_dev->parent)->ohci;
+
+	return 0;
+}
+
+static int sohci_free_dev(struct usb_device *usb_dev)
+{
 	int cnt;
     DECLARE_WAITQUEUE(wait, current);
-    struct ohci_device *dev = usb_to_ohci(usb_dev); 
-	
-	OHCI_DEBUG(printk("USB HC dealloc %x\n", usb_dev->devnum);)
- 	 
+	struct ohci_device *dev = usb_to_ohci(usb_dev);
+
+	OHCI_DEBUG(printk("USB HC ***** free %x\n", usb_dev->devnum);)
+
 	if(usb_dev->devnum >= 0) {
 		current->state = TASK_UNINTERRUPTIBLE;
     	cnt = usb_ohci_rm_function(usb_dev, sohci_blocking_handler, NULL, &wait);
@@ -281,109 +367,161 @@
     		schedule();
     		remove_wait_queue(&op_wakeup, &wait);
     	}
+    	current->state = TASK_INTERRUPTIBLE;
 	}
- 	 		 
-    USB_FREE(dev);
-    usb_destroy_configuration(usb_dev);
-	USB_FREE(usb_dev);
+
+if (atomic_dec_and_test(&dev->refcnt))
+		kfree(dev);
 
 	return 0;
 }
 
-static struct usb_device *sohci_usb_allocate(struct usb_device *parent) {
  
-	struct usb_device *usb_dev;
-	struct ohci_device *dev;
-	
-	USB_ALLOC(usb_dev, sizeof(*usb_dev));
-	if (!usb_dev)
-		return NULL;
-		
-	memset(usb_dev, 0, sizeof(*usb_dev));
 
-	USB_ALLOC(dev, sizeof(*dev));
-	if (!dev) {
-		usb_destroy_configuration(usb_dev);
-		USB_FREE(usb_dev);
-		return NULL;
-	}
+/*
+ * ISO Interface designed by Randy Dunlap
+ */
 
-	/* Initialize "dev" */
-	memset(dev, 0, sizeof(*dev));
+static int sohci_get_current_frame_number(struct usb_device *usb_dev) {
+
+	struct ohci * ohci = usb_dev->bus->hcpriv;
 	
-	usb_dev->hcpriv = dev;
-	dev->usb = usb_dev;
+	return readl(&ohci->regs->fmnumber) & 0xffff;
+}
 
-	usb_dev->parent = parent;
 
-	if (parent) {
-		usb_dev->bus = parent->bus;
-		dev->ohci = usb_to_ohci(parent)->ohci;
-	}
-	return usb_dev;
-}
+static int sohci_init_isoc(struct usb_device *usb_dev, unsigned int pipe, int frame_count, void *context, struct usb_isoc_desc **idp) {
 
-static void *sohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
-{
-	struct ohci * ohci = usb_dev->bus->hcpriv;
-	struct ohci_device * dev = usb_to_ohci(usb_dev);
-	struct usb_hcd_ed hcd_ed;
-	struct usb_ohci_ed * ed;
- 	struct usb_ohci_td * td;
- 	
-	usb_pipe_to_hcd_ed(usb_dev, pipe, &hcd_ed);
-	hcd_ed.type = ISO;
-	ed = usb_ohci_add_ep(usb_dev, &hcd_ed, 1, 1);
+	struct usb_isoc_desc *id;
 	
-	OHCI_DEBUG( printk("USB HC ISO>>>: %x:  \n", ed->hwINFO);) 
+	*idp = NULL;
+
+	id = kmalloc (sizeof (struct usb_isoc_desc) + (sizeof (struct isoc_frame_desc) * frame_count), GFP_KERNEL);
+	if(!id) return -ENOMEM;
+	memset (id, 0, sizeof (struct usb_isoc_desc) + (sizeof (struct isoc_frame_desc) * frame_count));
+OHCI_DEBUG(printk("ISO alloc id: %p, size: %d\n", id, sizeof (struct usb_isoc_desc) + (sizeof (struct isoc_frame_desc) * frame_count));)
+	id->td = kmalloc (sizeof (void *) * frame_count, GFP_KERNEL);
+	if(!id->td) {
+		kfree (id);
+		return -ENOMEM;
+	}		
+	memset (id->td, 0, sizeof (void *) * frame_count);
+OHCI_DEBUG(printk("ISO alloc id->td: %p, size: %d\n", id->td, sizeof (void *) * frame_count);)
 	
-	td = ohci_trans_req(ohci, ed, 0, NULL, dev->data, len, (__OHCI_BAG) completed, (__OHCI_BAG) dev_id, (usb_pipeout(pipe))?ISO_OUT:ISO_IN, sohci_int_handler);
-	return td;
-}
+	id->frame_count = frame_count;
+	id->frame_size  = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe));
+	id->start_frame = -1;
+	id->end_frame   = -1;
+	id->usb_dev     = usb_dev;
+	id->pipe        = pipe;
+	id->context     = context;
 
-static void sohci_delete_isochronous (struct usb_device *usb_dev, void *td)
-{
-	// struct ohci * ohci = usb_dev->bus->hcpriv; 
-	DECLARE_WAITQUEUE(wait, current);
+	*idp = id;
+	return 0;
+} 
+
+void print_int_eds(struct ohci * ohci);
+
+static int sohci_run_isoc(struct usb_isoc_desc *id, struct usb_isoc_desc *pr_id) {
+
+	struct ohci * ohci = id->usb_dev->bus->hcpriv;
+	struct usb_ohci_td  ** tdp = (struct usb_ohci_td  **) id->td;
+	struct usb_hcd_ed   hcd_ed;
+	struct usb_ohci_ed  * ed;
+	int	ix, frlen;
+	unsigned char	*bufptr;
+
+	if(pr_id)
+		id->start_frame = pr_id->end_frame + 1;		
+	else {
+		switch(id->start_type) {
+			case START_ABSOLUTE:
+				break;
+				
+			case START_RELATIVE:
+				if(id->start_frame < START_FRAME_FUDGE) id->start_frame = START_FRAME_FUDGE;
+				id->start_frame += sohci_get_current_frame_number(id->usb_dev);
+				break;
+				
+			case START_ASAP:
+				id->start_frame = START_FRAME_FUDGE + sohci_get_current_frame_number(id->usb_dev);
+				break;
+		}
+	}
+
+	id->start_frame &= 0xffff;	
+	id->end_frame = (id->start_frame + id->frame_count - 1) & 0xffff;
+
+	id->prev_completed_frame = 0;
+	id->cur_completed_frame  = 0;
+	if (id->frame_spacing <= 0) id->frame_spacing = 1;
+	
+	bufptr = id->data;
 	
-	OHCI_DEBUG( printk("USB HC RM_ISO>>>:%4x\n", (unsigned int) td);)
+	usb_pipe_to_hcd_ed(id->usb_dev, id->pipe, &hcd_ed);
+	hcd_ed.type = ISO;
+	ed = usb_ohci_add_ep(id->usb_dev, &hcd_ed, 1, 1);
+	OHCI_DEBUG( printk("USB HC ISO>>>: ed: %x-%x: (%d tds)\n", (unsigned int) ed, ed->hwINFO, id->frame_count);) 
 	 
-	current->state = TASK_UNINTERRUPTIBLE;
-    usb_ohci_rm_ep(usb_dev, ((struct usb_ohci_td *) td)->ed, sohci_blocking_handler, NULL, &wait, SEND);
-    schedule();
-    remove_wait_queue(&op_wakeup, &wait); 
-	return;
+	for (ix = 0; ix < id->frame_count; ix++) {
+		frlen = (id->frames[ix].frame_length > id->frame_size)? id->frame_size : id->frames[ix].frame_length;	
+		printk("ISO run id->td: %p \n", &tdp[ix]);
+		tdp[ix] = ohci_trans_req(ohci, ed, id->start_frame + ix , NULL, bufptr, frlen, (__OHCI_BAG) ix, (__OHCI_BAG) id, 
+						(usb_pipeout(id->pipe))?ISO_OUT:ISO_IN, 
+						sohci_iso_handler);
+		bufptr += frlen;
+	}
+	
+	if (ED_STATE(ed) != ED_OPER)  ohci_link_ed(ohci, ed);
+	print_int_eds(ohci);
+	return 0;
 }
 
-static int sohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
-{
-	return USB_ST_NOTSUPPORTED;
-}
+static int sohci_kill_isoc(struct usb_isoc_desc *id) {
 
-static int sohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc)
-{
-	return USB_ST_NOTSUPPORTED;
+	struct usb_ohci_ed	*ed = NULL;
+	struct usb_ohci_td	**td = id->td;
+	int i;
+printk("KILL_ISOC***:\n");	
+	for (i = 0; i < id->frame_count; i++) {
+		if(td[i]) {
+			td[i]->type |= DEL;
+			ed = td[i]->ed; printk(" %d", i);	
+		}
+	} 
+	if(ed) usb_ohci_rm_ep(id->usb_dev, ed, NULL, NULL, NULL, TD_RM);
+printk(": end KILL_ISOC***: %p\n", ed);		
+	id->start_frame = -1;
+	return 0;
 }
 
-static int sohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
-{
-	return USB_ST_NOTSUPPORTED;
+
+static void sohci_free_isoc(struct usb_isoc_desc *id) {
+printk("FREE_ISOC***\n");
+wait_ms(2000);
+	if(id->start_frame >= 0) sohci_kill_isoc(id);
+printk("FREE_ISOC2***\n");
+wait_ms(2000);
+	kfree(id->td);
+	kfree(id);
+printk("FREE_ISOC3***\n");
+wait_ms(2000);
 }
 
 struct usb_operations sohci_device_operations = {
-	sohci_usb_allocate,
-	sohci_usb_deallocate,
+	sohci_alloc_dev,
+	sohci_free_dev,
 	sohci_control_msg,
 	sohci_bulk_msg,
 	sohci_request_irq,
 	sohci_release_irq,
 	sohci_request_bulk,
 	sohci_terminate_bulk,
-	sohci_alloc_isochronous,
-	sohci_delete_isochronous,
-	sohci_sched_isochronous,
-	sohci_unsched_isochronous,
-	sohci_compress_isochronous
+	sohci_get_current_frame_number,
+	sohci_init_isoc,
+	sohci_free_isoc,
+	sohci_run_isoc,
+	sohci_kill_isoc
 };
 
  
@@ -394,7 +532,7 @@
 /* just for debugging; prints all 32 branches of the int ed tree inclusive iso eds*/
 void print_int_eds(struct ohci * ohci) {int i; __u32 * ed_p;
 	for(i= 0; i < 32; i++) {
-			OHCI_DEBUG(printk("unlnk_branch int %2d(%2x): ", i,i); )
+			OHCI_DEBUG(printk("branch int %2d(%2x): ", i,i); )
 			ed_p = &(ohci->hc_area->hcca.int_table[i]);
 			while (*ed_p != 0) {
 				OHCI_DEBUG(printk("ed: %4x; ", (((struct usb_ohci_ed *)bus_to_virt(*ed_p))->hwINFO));)
@@ -431,7 +569,7 @@
 }
 
 /* the int tree is a binary tree 
- * in order to process it sequentielly the indexes of the branches have to be mapped 
+ * in order to process it sequentially the indexes of the branches have to be mapped 
  * the mapping reverses the bits of a word of num_bits length
  * */
 static int rev(int num_bits, int word) {
@@ -445,7 +583,7 @@
 /* get the ed from the endpoint / usb_device address */
 
 struct usb_ohci_ed * ohci_find_ep(struct usb_device *usb_dev, struct usb_hcd_ed *hcd_ed) {
- 	return &(usb_to_ohci(usb_dev)->ed[hcd_ed->endpoint << 1 | ((hcd_ed->type == CTRL)? 0:hcd_ed->out)]);
+ 	return &(usb_to_ohci(usb_dev)->ed[(hcd_ed->endpoint << 1) | ((hcd_ed->type == CTRL)? 0:hcd_ed->out)]);
 }
 
 /* link an ed into one of the HC chains */
@@ -634,16 +772,19 @@
 
    	// struct ohci * ohci = usb_dev->bus->hcpriv;
 	struct usb_ohci_td * td;  
-	struct usb_ohci_ed * ed; 
+	struct usb_ohci_ed * ed, *ed1; 
 	 
- 	int ed_state;
+ 	int ed_state, ed_state1;
  
 	spin_lock(&usb_ed_lock);
 
-	ed = ohci_find_ep(usb_dev, hcd_ed);
+	ed = ohci_find_ep(usb_dev, hcd_ed); 
 
+	 
+	ed1 = ((void *) ed) + 0x40; ed_state1 = ED_STATE(ed1);
+OHCI_DEBUG(printk("++++ USB HC add 60 ed1 %x: %x :state: %x\n", ed1->hwINFO, (unsigned int ) ed1, ed_state1); )
 	ed_state = ED_STATE(ed); /* store state of ed */
-	
+	OHCI_DEBUG(printk("USB HC add ed %x: %x :state: %x\n", ed->hwINFO, (unsigned int ) ed, ed_state); )
 	if (ed_state == ED_NEW) {
   		OHCI_ALLOC(td, sizeof(*td)); /* dummy td; end of td list for ed */
 		ed->hwTailP = virt_to_bus(td);
@@ -678,6 +819,8 @@
  * put the ep on the rm_list and request a stop of the bulk or ctrl list 
  * real removal is done at the next start of frame (SOF) hardware interrupt 
  * the dummy td carries the essential information (handler, proc queue, ...)
+ * if(send & TD_RM) then just the TD witch have (TD->type & DEL) set will be removed
+ * otherwise all TDs including the dummy TD of the ED will be removed
  */
 int usb_ohci_rm_ep(struct usb_device * usb_dev, struct usb_ohci_ed *ed, f_handler handler, __OHCI_BAG lw0, __OHCI_BAG lw1, int send)
 {    
@@ -692,17 +835,21 @@
 	ed->hwINFO  |=  OHCI_ED_SKIP;
 	writel( OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
 
-	if(ED_STATE(ed) == ED_OPER) ohci_unlink_ed(ohci, ed);
 
-	td = (struct usb_ohci_td *) bus_to_virt(ed->hwTailP);
-	td->lw0 = lw0;
-	td->lw1 = lw1;
-	td->ed = ed;
-	td->hwINFO = TD_CC;
-	td->handler = handler;
-	td->type = send;
-  
-	ED_setSTATE(ed, ED_DEL);
+	if(send & TD_RM) { /* delete selected TDs */
+		ED_setSTATE(ed, ED_TD_DEL);
+	}
+	else { /* delete all TDS */
+		if(ED_STATE(ed) == ED_OPER) ohci_unlink_ed(ohci, ed);
+		td = (struct usb_ohci_td *) bus_to_virt(ed->hwTailP);
+		td->lw0 = lw0;
+		td->lw1 = lw1;
+		td->ed = ed;
+		td->hwINFO = TD_CC;
+		td->handler = handler;
+		td->type = send; 
+		ED_setSTATE(ed, ED_DEL);
+	}
 	ed->ed_prev = ohci->ed_rm_list;
 	ohci->ed_rm_list = ed;
    
@@ -770,7 +917,7 @@
 
 #define FILL_ISO_TD(INFO, DATA, LEN, LW0, LW1, TYPE, HANDLER)  \
 	OHCI_ALLOC(td_pt, sizeof(*td_pt)); \
-    td_ret = (struct usb_ohci_td *) bus_to_virt(usb_ed->hwTailP); \
+    td_ret = (struct usb_ohci_td *) bus_to_virt(usb_ed->hwTailP & 0xfffffff0); \
     td_pt1 = td_ret; \
     td_pt1->ed = ed; \
     td_pt1->buffer_start = (DATA); \
@@ -779,12 +926,13 @@
     td_pt1->lw0 = (LW0); \
     td_pt1->lw1 = (LW1); \
     td_pt1->hwINFO = (INFO); \
-    td_pt1->hwCBP = (virt_to_bus(DATA) & 0xfffff000); \
-    td_pt1->hwBE = virt_to_bus((DATA) + (LEN) - 1); \
+    td_pt1->hwCBP = (((DATA)==NULL)||((LEN)==0))?0:(virt_to_bus(DATA) & 0xfffff000); \
+    td_pt1->hwBE = (((DATA)==NULL)||((LEN)==0))?0:virt_to_bus((DATA) + (LEN) - 1); \
     td_pt1->hwNextTD = virt_to_bus(td_pt); \
-    td_pt1->hwPSW[0] = virt_to_bus(DATA) & 0xfff; \
-    usb_ed->hwTailP = virt_to_bus(td_pt); \
-    td_pt->hwNextTD = 0
+    td_pt1->hwPSW[0] = (virt_to_bus(DATA) & 0xfff) | 0xe000; \
+    td_pt->hwNextTD = 0; \
+    usb_ed->hwTailP =  td_pt1->hwNextTD
+    
     
 spinlock_t usb_req_lock = SPIN_LOCK_UNLOCKED;
 
@@ -811,7 +959,7 @@
   case BULK_IN: 
   	while(data_len > 4096)
 	{	
-		FILL_TD( TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, 4096, NULL, NULL, BULK_IN | ADD_LEN|(cnt++?0:ST_ADDR), NULL);
+		FILL_TD( TD_CC | TD_DP_IN | TD_T_TOGGLE, data, 4096, NULL, NULL, BULK_IN | ADD_LEN|(cnt++?0:ST_ADDR), NULL);
 		data += 4096; data_len -= 4096;
 	}
     FILL_TD( TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1, BULK_IN |ADD_LEN|SEND|(cnt++?0:ST_ADDR), handler);
@@ -925,7 +1073,8 @@
 }
 
 /* there are some pending requests to remove some of the eds 
- * we process every td including the dummy td of these eds 
+ * we either process every td including the dummy td of these eds 
+ * or just those marked with TD->type&DEL
  * and link them to a list
  * */
 static struct usb_ohci_td * usb_ohci_del_list(struct ohci *  ohci) {
@@ -964,11 +1113,12 @@
    	 	 	OHCI_DEBUG(printk("USB HC ed_rm_list: dummy (ED_DEL) td: %4x\n", (unsigned int) td);)
    	 	 	ED_setSTATE(td->ed, ED_DEL| ED_NEW);
    	 	 	td->next_dl_td = NULL;
-   	 	}	
+   	 	}	  	
+   	 	if(ED_TYPE(ed) == CTRL) writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
+  		if(ED_TYPE(ed) == BULK) writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
+
    	}  
    	  
-  	writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
-  	writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
   	writel_set((0x03<<4), &ohci->regs->control);   /* start CTRL u. BULK list */ 
 
    	ohci->ed_rm_list = NULL;
@@ -1014,11 +1164,11 @@
   			}
   		}
   		/* error code of transfer */
-  		cc = (ED_STATE(td_list->ed) == ED_DEL || (td_list->type & DEL))? USB_ST_REMOVED : TD_CC_GET(td_list->hwINFO);
+  		cc = (ED_STATE(td_list->ed) == ED_DEL || (td_list->type & DEL))? USB_ST_REMOVED : (USB_ST_CRC*TD_CC_GET(td_list->hwINFO));
 
   	 	if(td_list->type & DEL_ED) ED_setSTATE(td_list->ed, ED_NEW); /* remove ed */
  		
-  		if((td_list->type & SEND) && (ED_STATE(td_list->ed) != ED_STOP)) {  /*  send the reply  */	
+  		if((td_list->type & SEND) && (ED_STATE(td_list->ed) != ED_STOP) && (td_list->handler)) {  /*  send the reply  */	
   			td_list->handler((void *) ohci,
 						td_list->ed,				  
 						td_list->ed->buffer_start, 
@@ -1029,6 +1179,7 @@
 			OHCI_DEBUG(if(cc != TD_CC_NOERROR) printk("******* USB BUS error %x @ep %x\n", TD_CC_GET(td_list->hwINFO), td_list->ed->hwINFO);)		
 			
 		}
+		if(ED_STATE(td_list->ed) == ED_TD_DEL) td_list->ed->hwINFO &= ~OHCI_ED_SKIP;
 		
      	if(((td_list->ed->hwHeadP & 0xfffffff0) == td_list->ed->hwTailP) && (ED_STATE(td_list->ed) > ED_UNLINK)) 
      		ohci_unlink_ed(ohci, td_list->ed); 		/* unlink eds if they are not busy */
@@ -1050,12 +1201,18 @@
 void reset_hc(struct ohci *ohci) {
 
 	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
 	 	
 	if(readl(&ohci->regs->control) & 0x100) { /* SMM owns the HC */
 		writel(0x08,  &ohci->regs->cmdstatus); /* request ownership */
 		printk("USB HC TakeOver from SMM\n");
-		if(readl(&ohci->regs->control) & 0x100)
-			printk("USB HC TakeOver failed!\n");
+		while(readl(&ohci->regs->control) & 0x100) {
+			wait_ms(10);
+			if (--smm_timeout == 0) {
+				printk("USB HC TakeOver failed!\n");
+				break;
+			}
+		}
 	}	
 		
 	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
@@ -1092,7 +1249,7 @@
 	
 	writel(virt_to_bus(&ohci->hc_area->hcca), &ohci->regs->hcca); /* a reset clears this */
    
-	writel((0xB7), &ohci->regs->control); /* USB Operational */
+	writel((0xBF), &ohci->regs->control); /* USB Operational */
  		
   	fminterval = 0x2edf;
 	writel(((fminterval)*9)/10, &ohci->regs->periodicstart);
@@ -1121,16 +1278,16 @@
 	struct ohci_device *dev;
  
 
-	usb_dev = sohci_usb_allocate(NULL);
+	usb_dev = usb_alloc_dev(NULL, ohci->bus);
 	if (!usb_dev) return -1;
 
 	dev = usb_to_ohci(usb_dev);
-	usb_dev->bus = ohci->bus;
+	// usb_dev->bus = ohci->bus;
 	ohci->bus->root_hub = usb_dev;
 	dev->ohci = ohci;
 	usb_connect(usb_dev);
 	if(usb_new_device(usb_dev) != 0) {
-		sohci_usb_deallocate(usb_dev); 
+		usb_free_dev(usb_dev); 
 		return -1;
 	}
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/ohci-hcd.h linux/drivers/usb/ohci-hcd.h
--- v2.3.17/linux/drivers/usb/ohci-hcd.h	Wed Aug 18 16:22:23 1999
+++ linux/drivers/usb/ohci-hcd.h	Fri Sep 10 12:59:49 1999
@@ -22,7 +22,7 @@
  * ohci-hcd.h
  */
  
-// #define OHCI_DBG    /* printk some debug information */
+#define OHCI_DBG    /* printk some debug information */
 
  
 #include <linux/config.h>
@@ -62,6 +62,7 @@
 #define ED_OPER		0x02
 #define ED_STOP     0x03
 #define ED_DEL		0x04
+#define ED_TD_DEL	0x05
 #define ED_RH		0x07 /* marker for RH ED */
 
 #define ED_STATE(ed) 			(((ed)->hwINFO >> 29) & 0x7)
@@ -182,6 +183,7 @@
 #define ADD_LEN         0x00004000
 #define DEL             0x00008000
 #define DEL_ED          0x00040000
+#define TD_RM			0x00080000
 
 #define OHCI_ED_SKIP	(1 << 14)
  
@@ -332,6 +334,7 @@
 };
 struct ohci_device {
 	struct usb_device	*usb;
+	atomic_t			refcnt;
 	struct ohci			*ohci;
 	struct usb_ohci_ed	ed[NUM_EDS];
 	unsigned long		data[16];
@@ -351,7 +354,7 @@
 
 int root_hub_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len);
 int root_hub_release_irq(struct usb_device *usb_dev, void * ed);  
-void * root_hub_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id);
+int root_hub_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle);
 
 /* Root-Hub Register info */
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/ohci-root-hub.c linux/drivers/usb/ohci-root-hub.c
--- v2.3.17/linux/drivers/usb/ohci-root-hub.c	Wed Aug 18 16:22:23 1999
+++ linux/drivers/usb/ohci-root-hub.c	Fri Sep 10 12:59:49 1999
@@ -234,10 +234,6 @@
 	OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));)
 	OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));)
   		
-	OHCI_DEBUG( { int i; printk("USB HC RH bh <<<: 1: ");)
-	OHCI_DEBUG( printk(" data(%d):", len);) 
-	OHCI_DEBUG( { for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
-	OHCI_DEBUG( printk(" ret_status: %x\n", req_reply); })
 	
 	return req_reply;
 }
@@ -285,10 +281,7 @@
 		len = root_hub_send_irq(ohci, dev->data, 1 );
 
 		if(len > 0) { 
-			OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: RH data(%d):", len);)
-			OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) dev->data)[i]);)
-			OHCI_DEBUG( printk(" ret_status: %x\n", 0); })
- 
+			
 			ret = ohci->rh.handler(0, dev->data, len, ohci->rh.dev_id);
 			if(ret <= 0)ohci->rh.send = 0; /* 0 .. do not requeue  */
 		}
@@ -316,7 +309,7 @@
 	return 0;
 }
  
-void * root_hub_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) 
+int root_hub_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
 {
 	struct ohci * ohci = usb_dev->bus->hcpriv;
 	
@@ -326,7 +319,8 @@
 	ohci->rh.send = 1;
 	ohci->rh.interval = period;
 	ohci_init_rh_int_timer(usb_dev, period);
-	return ohci->rh.int_addr = usb_to_ohci(usb_dev);
+	*handle = ohci->rh.int_addr = usb_to_ohci(usb_dev);
+	return 0;
 }
 
 int root_hub_release_irq(struct usb_device *usb_dev, void * ed) 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.17/linux/drivers/usb/ohci.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/ohci.c	Fri Sep 10 12:59:49 1999
@@ -37,8 +37,8 @@
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
+#include <linux/spinlock.h>
 
-#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -943,11 +943,12 @@
  * Period is desired polling interval in ms.  The closest, shorter
  * match will be used.  Powers of two from 1-32 are supported by OHCI.
  *
- * Returns: a "handle pointer" that release_irq can use to stop this
- * interrupt.  (It's really a pointer to the TD).  NULL = error.
+ * Returns: success (0) or failure (< 0).
+ * Also sets the "handle pointer" that release_irq can use to stop this
+ * interrupt.  (It's really a pointer to the TD).
  */
-static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
-	usb_device_irq handler, int period, void *dev_id)
+static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
+	usb_device_irq handler, int period, void *dev_id, void **handle)
 {
 	struct ohci_device *dev = usb_to_ohci(usb);
 	struct ohci_td *td;
@@ -961,7 +962,7 @@
 		interrupt_ed = ohci_get_free_ed(dev);
 		if (!interrupt_ed) {
 			printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
-			return NULL;
+			return (-ENOMEM);
 		}
 
 		/*
@@ -988,7 +989,7 @@
 	if (!td) {
 		printk(KERN_ERR "Out of TDs in ohci_request_irq\n");
 		ohci_free_ed(interrupt_ed);
-		return NULL;
+		return (-ENOMEM);
 	}
 
 	/* Fill in the TD */
@@ -1009,7 +1010,8 @@
 	td = ohci_add_tds_to_ed(td, interrupt_ed);
 	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 
-	return (void*)td;
+	*handle = (void*)td;
+	return 0;
 } /* ohci_request_irq() */
 
 /*
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.17/linux/drivers/usb/printer.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/usb/printer.c	Wed Sep  8 11:51:22 1999
@@ -16,8 +16,7 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/lp.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include "usb.h"
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/proc_usb.c linux/drivers/usb/proc_usb.c
--- v2.3.17/linux/drivers/usb/proc_usb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/usb/proc_usb.c	Fri Sep 10 12:59:49 1999
@@ -64,6 +64,10 @@
 static char *format_topo =
 /* T:  Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd If#=ddd MxCh=dd Driver=%s */
   "T:  Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s If#=%3d MxCh=%2d Driver=%s\n";
+
+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 */
@@ -193,10 +197,7 @@
  * 0. TBDs
  * 1. marking active config and ifaces (code lists all, but should mark
  *    which ones are active, if any)
- * 2. Add proc_usb_init() call from usb-core.c.
- * 3. proc_usb as a MODULE ?
- * 4. use __init ?
- * 5. add <halted> status to each endpoint line
+ * 2. add <halted> status to each endpoint line
  */
 
 static int usb_dump_config_descriptor (const struct usb_config_descriptor *desc,
@@ -282,6 +283,17 @@
 	return 0;
 }
 
+static int usb_hcd_bandwidth (const struct usb_device *dev, char *buf, int *len)
+{
+	*len += sprintf (buf + *len, format_bandwidth,
+			dev->bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC,
+			100 * dev->bus->bandwidth_allocated / FRAME_TIME_MAX_USECS_ALLOC,
+			dev->bus->bandwidth_int_reqs, dev->bus->bandwidth_isoc_reqs
+			);
+
+	return (*len >= DUMP_LIMIT) ? -1 : 0;
+}
+
 #ifdef PROC_EXTRA /* TBD: may want to add this code later */
 
 static int usb_dump_hub_descriptor (const struct usb_hub_descriptor * desc,
@@ -352,6 +364,10 @@
 		if (usb_dump_desc (usbdev, buf, len) < 0)
 			return -1;
 	}
+	else {		/* for a host controller */
+		if (usb_hcd_bandwidth (usbdev, buf, len) < 0)
+			return -1;
+	}
 
 	/* Now look at all of this device's children. */
 	for (chix = 0; chix < usbdev->maxchild; chix++) {
@@ -850,19 +866,5 @@
 
 	return 0;
 }
-
-#ifdef PROCFS_MODULE /* TBD: support proc_fs MODULE ??? */
-
-int init_module (void)
-{
-	return proc_usb_init ();
-}
-
-void cleanup_module (void)
-{
-	proc_usb_cleanup ();
-}
-
-#endif /* PROCFS_MODULE */
 
 /* end proc_usb.c */
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.17/linux/drivers/usb/uhci.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/uhci.c	Fri Sep 10 12:59:49 1999
@@ -41,9 +41,9 @@
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
 #include <linux/unistd.h>
+#include <linux/spinlock.h>
 
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -589,28 +589,33 @@
 /*
  * Request a interrupt handler..
  *
- * Returns: a "handle pointer" that release_irq can use to stop this
+ * Returns 0 (success) or negative (failure).
+ * Also returns/sets a "handle pointer" that release_irq can use to stop this
  * interrupt.  (It's really a pointer to the TD).
  */
-static void *uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci_td *td = uhci_td_alloc(dev);
 	struct uhci_qh *qh = uhci_qh_alloc(dev);
 	unsigned int destination, status;
 
-	if (!td || !qh)
-		return NULL;
+	if (!td || !qh) {
+		if (td)
+			uhci_td_free(td);
+		if (qh)
+			uhci_qh_free(qh);
+		return (-ENOMEM);
+	}
 
 	/* Destination: pipe destination with INPUT */
 	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe);
 
 	/* Infinite errors is 0, so no bits */
-	status = (pipe & TD_CTRL_LS) | TD_CTRL_IOC | TD_CTRL_ACTIVE |
-			TD_CTRL_SPD;
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_IOC | TD_CTRL_ACTIVE | TD_CTRL_SPD;
 
 	td->link = UHCI_PTR_TERM;		/* Terminate */
-	td->status = status;			/* In */
+	td->status = status;
 	td->info = destination | ((usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)) - 1) << 21) |
 		(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE);
 
@@ -632,7 +637,8 @@
 	/* Add it into the skeleton */
 	uhci_insert_qh(qh->skel, qh);
 
-	return (void *)td;
+	*handle = (void *)td;
+	return 0;
 }
 
 /*
@@ -684,7 +690,6 @@
 /*
  * uhci_init_isoc()
  *
- * Checks bus bandwidth allocation for this USB bus.
  * Allocates some data structures.
  * Initializes parts of them from the function parameters.
  *
@@ -705,11 +710,6 @@
 	struct usb_isoc_desc *id;
 	int i;
 
-#ifdef BANDWIDTH_ALLOCATION
-	/* TBD: add bandwidth allocation/checking/management HERE. */
-	/* TBD: some way to factor in frame_spacing ??? */
-#endif
-
 	*isocdesc = NULL;
 
 	/* Check some parameters. */
@@ -860,24 +860,13 @@
 			if (ix < START_FRAME_FUDGE || /* too small */
 			    ix > CAN_SCHEDULE_FRAMES) { /* too large */
 #ifdef CONFIG_USB_DEBUG_ISOC
-					printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n",
-						isocdesc->start_frame);
+					printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d,%d)\n",
+						isocdesc->start_frame, cur_frame);
 #endif
 					return -EINVAL;
-				}
-			}
-			else /* start_frame <= cur_frame */ {
-				if ((isocdesc->start_frame + UHCI_MAX_SOF_NUMBER + 1
-				    - cur_frame) > CAN_SCHEDULE_FRAMES) {
-#ifdef CONFIG_USB_DEBUG_ISOC
-					printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n",
-						isocdesc->start_frame);
-#endif
-					return -EINVAL;
-				}
 			}
 		} /* end START_ABSOLUTE */
-	}
+	} /* end not pr_isocdesc */
 
 	/*
 	 * Set the start/end frame numbers.
@@ -1395,7 +1384,7 @@
 		if (pktsze > maxsze)
 			pktsze = maxsze;
 
-		td->status = status;                                    /* Status */
+		td->status = status;
 		td->info = destination | ((pktsze-1) << 21) |
 			(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); /* pktsze bytes of data */
 		td->buffer = virt_to_bus(data);
@@ -1726,6 +1715,8 @@
 	 * interrupt cause
 	 */
 	status = inw(io_addr + USBSTS);
+	if (!status)	/* shared interrupt, not mine */
+		return;
 	outw(status, io_addr + USBSTS);
 
 	/* Walk the list of pending TD's to see which ones completed.. */
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.17/linux/drivers/usb/usb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/usb/usb.c	Fri Sep 10 12:59:49 1999
@@ -13,6 +13,8 @@
  * are evil.
  */
 
+#define USB_DEBUG	1
+
 #include <linux/config.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
@@ -110,6 +112,82 @@
 }
 
 /*
+ * calc_bus_time:
+ *
+ * returns (approximate) USB bus time in nanoseconds for a USB transaction.
+ */
+static long calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
+{
+	unsigned long	tmp;
+
+	if (low_speed)		/* no isoc. here */
+	{
+		if (input_dir)
+                {
+		        tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
+		}
+		else
+                {
+			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
+		}
+	}
+
+	/* for full-speed: */
+
+	if (!isoc)		/* Input or Output */
+	{
+		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+		return (9107L + BW_HOST_DELAY + tmp);
+	} /* end not Isoc */
+
+	/* for isoc: */
+
+	tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+	return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
+} /* end calc_bus_time */
+
+/*
+ * check_bandwidth_alloc():
+ *
+ * old_alloc is from host_controller->bandwidth_allocated in microseconds;
+ * bustime is from calc_bus_time(), but converted to microseconds.
+ *
+ * returns 0 if successful,
+ * -1 if bandwidth request fails.
+ *
+ * FIXME:
+ * This initial implementation does not use Endpoint.bInterval
+ * in managing bandwidth allocation.
+ * It probably needs to be expanded to use Endpoint.bInterval.
+ * This can be done as a later enhancement (correction).
+ * This will also probably require some kind of
+ * frame allocation tracking...meaning, for example,
+ * that if multiple drivers request interrupts every 10 USB frames,
+ * they don't all have to be allocated at
+ * frame numbers N, N+10, N+20, etc.  Some of them could be at
+ * N+11, N+21, N+31, etc., and others at
+ * N+12, N+22, N+32, etc.
+ * However, this first cut at USB bandwidth allocation does not
+ * contain any frame allocation tracking.
+ */
+int check_bandwidth_alloc (unsigned int old_alloc, long bustime)
+{
+	unsigned int	new_alloc;
+
+	new_alloc = old_alloc + bustime;
+		/* what new total allocated bus time would be */
+
+	PRINTD ("usb-bandwidth-alloc: was: %ld, new: %ld, bustime = %ld us, Pipe allowed: %s",
+		old_alloc, new_alloc, bustime,
+		(new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ?
+			"yes" : "no");
+
+	return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? 0 : -1;
+} /* end check_bandwidth_alloc */
+
+/*
  * New functions for (de)registering a controller
  */
 struct usb_bus *usb_alloc_bus(struct usb_operations *op)
@@ -125,6 +203,9 @@
 	bus->op = op;
 	bus->root_hub = NULL;
 	bus->hcpriv = NULL;
+	bus->bandwidth_allocated = 0;
+	bus->bandwidth_int_reqs  = 0;
+	bus->bandwidth_isoc_reqs = 0;
 
 	INIT_LIST_HEAD(&bus->bus_list);
 
@@ -237,9 +318,9 @@
 {
 	if (atomic_dec_and_test(&dev->refcnt)) {
 		usb_destroy_configuration(dev);
-		kfree(dev);
 
 		dev->bus->op->deallocate(dev);
+		kfree(dev);
 	}
 }
 
@@ -609,7 +690,7 @@
 	int i = 5;
 	int result;
 
-	dr.requesttype = 0x80;
+	dr.requesttype = USB_DIR_IN;
 	dr.request = USB_REQ_GET_DESCRIPTOR;
 	dr.value = (type << 8) + index;
 	dr.index = 0;
@@ -627,7 +708,7 @@
 {
 	devrequest dr;
 
-	dr.requesttype = 0x80;
+	dr.requesttype = USB_DIR_IN;
 	dr.request = USB_REQ_GET_DESCRIPTOR;
 	dr.value = (USB_DT_STRING << 8) + index;
 	dr.index = langid;
@@ -667,7 +748,7 @@
 	unsigned char buf[8];
 	devrequest dr;
 
-	dr.requesttype = USB_RT_HIDD | 0x80;
+	dr.requesttype = USB_RT_HIDD | USB_DIR_IN;
 	dr.request = USB_REQ_GET_PROTOCOL;
 	dr.value = 0;
 	dr.index = 1;
@@ -764,7 +845,7 @@
 	    return result;
 
 #if 1	/* let's be really tough */
-	dr.requesttype = 0x80 | USB_RT_ENDPOINT;
+	dr.requesttype = USB_DIR_IN | USB_RT_ENDPOINT;
 	dr.request = USB_REQ_GET_STATUS;
 	dr.length = 2;
 	status = 0xffff;
@@ -840,7 +921,7 @@
 {
 	devrequest dr;
 
-	dr.requesttype = USB_RT_HIDD | 0x80;
+	dr.requesttype = USB_RT_HIDD | USB_DIR_IN;
 	dr.request = USB_REQ_GET_REPORT;
 	dr.value = (type << 8) + id;
 	dr.index = index;
@@ -1047,9 +1128,32 @@
         return dev->bus->op->control_msg(dev, pipe, &dr, data, size);
 }
 
-void *usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
 {
-	return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
+	long    bustime;
+	int	ret;
+
+	*handle = NULL;
+
+	/* Check host controller's bandwidth for this int. request. */
+	bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0,
+			usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
+	bustime = NS_TO_US(bustime);	/* work in microseconds */
+	if (check_bandwidth_alloc (dev->bus->bandwidth_allocated, bustime))
+		return (USB_ST_BANDWIDTH_ERROR);
+
+	ret = dev->bus->op->request_irq(dev, pipe, handler, period, dev_id, handle);
+
+	/* Claim the USB bandwidth if no error. */
+	if (!ret) {
+		dev->bus->bandwidth_allocated += bustime;
+		dev->bus->bandwidth_int_reqs++;
+		PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+			dev->bus->bandwidth_allocated,
+			dev->bus->bandwidth_int_reqs);
+	}
+
+	return ret;
 }
 
 void *usb_request_bulk(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, void *data, int len, void *dev_id)
@@ -1062,9 +1166,26 @@
 	return dev->bus->op->terminate_bulk(dev, first);
 }
 
-int usb_release_irq(struct usb_device *dev, void *handle)
+int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe)
 {
-	return dev->bus->op->release_irq(dev, handle);
+	long    bustime;
+	int	err;
+
+	err = dev->bus->op->release_irq(dev, handle);
+
+	/* Return the USB bandwidth if no error. */
+	if (!err) {
+		bustime = calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe), 0,
+				usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
+		bustime = NS_TO_US(bustime);
+		dev->bus->bandwidth_allocated -= bustime;
+		dev->bus->bandwidth_int_reqs--;
+		PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+			dev->bus->bandwidth_allocated,
+			dev->bus->bandwidth_int_reqs);
+	}
+
+	return err;
 }
 
 /*
@@ -1084,11 +1205,46 @@
 			void *context,
 			struct usb_isoc_desc **isocdesc)
 {
-	return usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc);
+	long    bustime;
+	int	err;
+
+	/* Check host controller's bandwidth for this Isoc. request. */
+	/* TBD: some way to factor in frame_spacing ??? */
+	bustime = calc_bus_time (0, usb_pipein(pipe), 1,
+			usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)));
+	bustime = NS_TO_US(bustime);	/* work in microseconds */
+	if (check_bandwidth_alloc (usb_dev->bus->bandwidth_allocated, bustime))
+		return USB_ST_BANDWIDTH_ERROR;
+
+	err = usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc);
+
+	/* Claim the USB bandwidth if no error. */
+	if (!err) {
+		usb_dev->bus->bandwidth_allocated += bustime;
+		usb_dev->bus->bandwidth_isoc_reqs++;
+		PRINTD ("bw_alloc bumped to %d for %d requesters\n",
+			usb_dev->bus->bandwidth_allocated,
+			usb_dev->bus->bandwidth_isoc_reqs);
+	}
+
+	return err;
 }
 
 void usb_free_isoc (struct usb_isoc_desc *isocdesc)
 {
+	long    bustime;
+
+	/* Return the USB bandwidth. */
+	bustime = calc_bus_time (0, usb_pipein(isocdesc->pipe), 1,
+			usb_maxpacket(isocdesc->usb_dev, isocdesc->pipe,
+			usb_pipeout(isocdesc->pipe)));
+	bustime = NS_TO_US(bustime);
+	isocdesc->usb_dev->bus->bandwidth_allocated -= bustime;
+	isocdesc->usb_dev->bus->bandwidth_isoc_reqs--;
+	PRINTD ("bw_alloc reduced to %d for %d requesters\n",
+		isocdesc->usb_dev->bus->bandwidth_allocated,
+		isocdesc->usb_dev->bus->bandwidth_isoc_reqs);
+
 	isocdesc->usb_dev->bus->op->free_isoc (isocdesc);
 }
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.17/linux/drivers/usb/usb.h	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/usb.h	Fri Sep 10 12:59:49 1999
@@ -201,6 +201,7 @@
 #define USB_ST_NOTSUPPORTED	-2
 #define USB_ST_BANDWIDTH_ERROR	-3
 
+
 /*
  * USB device number allocation bitmap. There's one bitmap
  * per USB tree.
@@ -372,7 +373,8 @@
 				   current callback function ret. values */
 	CB_REUSE,               /* leave descriptors as NULL, not active */
 	CB_RESTART,             /* leave descriptors as they are, alive */
-	CB_ABORT                /* kill this USB transfer request */
+	CB_ABORT,                /* kill this USB transfer request */
+	CB_CONT_RUN    		/* append the isoc_desc at the end of all active isoc_desc */
 };
 
 struct isoc_frame_desc {
@@ -406,6 +408,7 @@
 	usb_device_irq  callback_fn;
 	void            *data;
 	int             buf_size;
+	struct usb_isoc_desc *prev_isocdesc; /* previous isoc_desc, for CB_CONT_RUN */
 	/*
 	 * The following fields are set by the usb_run_isoc() call.
 	 */
@@ -428,7 +431,7 @@
 	int (*deallocate)(struct usb_device *);
 	int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int);
 	int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
-	void *(*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+	int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
 	int (*release_irq)(struct usb_device *, void *);
 	void *(*request_bulk)(struct usb_device *, unsigned int, usb_device_irq,
  void *, int, void *);
@@ -451,6 +454,14 @@
 	struct list_head bus_list;
 	void *hcpriv;                   /* Host Controller private data */
 
+	unsigned int bandwidth_allocated; /* on this Host Controller; */
+					  /* applies to Int. and Isoc. pipes; */
+					  /* measured in microseconds/frame; */
+					  /* range is 0..900, where 900 = */
+					  /* 90% of a 1-millisecond frame */
+	int bandwidth_int_reqs;		/* number of Interrupt requesters */
+	int bandwidth_isoc_reqs;	/* number of Isoc. requesters */
+
 	/* procfs entry */
 	int proc_busnum;
 	struct proc_dir_entry *proc_entry;
@@ -520,8 +531,8 @@
 
 extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size);
 
-extern void *usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
-extern int usb_release_irq(struct usb_device *dev, void *handle);
+extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *, void **);
+extern int usb_release_irq(struct usb_device *dev, void *handle, unsigned int pipe);
 
 extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *);
 extern int usb_terminate_bulk(struct usb_device *, void *);
@@ -651,6 +662,26 @@
 int usb_clear_halt(struct usb_device *dev, int endp);
 
 /*
+ * Some USB bandwidth allocation constants.
+ */
+#define BW_HOST_DELAY	1000L		/* nanoseconds */
+#define BW_HUB_LS_SETUP	333L		/* nanoseconds */
+                        /* 4 full-speed bit times (est.) */
+
+#define FRAME_TIME_BITS         12000L		/* frame = 1 millisecond */
+#define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
+#define FRAME_TIME_USECS	1000L
+#define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
+
+#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
+		/* Trying not to use worst-case bit-stuffing
+                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+		/* bytecount = data payload byte count */
+
+#define NS_TO_US(ns)	((ns + 500L) / 1000L)
+			/* convert & round nanoseconds to microseconds */
+
+/*
  * Debugging helpers..
  */
 void usb_show_device_descriptor(struct usb_device_descriptor *);
@@ -661,6 +692,14 @@
 void usb_show_device(struct usb_device *);
 void usb_show_string(struct usb_device *dev, char *id, int index);
 
+#ifdef USB_DEBUG
+#define PRINTD(format, args...) printk("usb: " format "\n" , ## args);
+#else /* NOT DEBUGGING */
+#define PRINTD(fmt, arg...) do {} while (0) /**/
+#endif /* USB_DEBUG */
+/* A simple way to change one line from DEBUG to NOT DEBUG: */
+#define XPRINTD(fmt, arg...)	do {} while (0)
+
 /*
  * procfs stuff
  */
@@ -677,7 +716,7 @@
 extern inline void proc_usb_remove_device(struct usb_device *dev) {}
 #endif
 
-#endif  /* __KERNEL */
+#endif  /* __KERNEL__ */
 
 #endif
 
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.17/linux/drivers/usb/usb_scsi.c	Tue Sep  7 12:14:07 1999
+++ linux/drivers/usb/usb_scsi.c	Fri Sep 10 12:59:49 1999
@@ -36,8 +36,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 
 #include <linux/blk.h>
@@ -93,6 +92,7 @@
 	int			pid;			/* control thread */
 	struct semaphore      	*notify; 		/* wait for thread to begin */
 	void			*irq_handle;		/* for USB interrupt requests */
+	unsigned int		irqpipe;		/* remember pipe for release_irq */
 };
 
 /*
@@ -375,7 +375,6 @@
     __u8 status[2];
     devrequest dr;
     int retry = 5;
-    void *irq_handle;
 
     US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
     switch (us->protocol) {
@@ -383,7 +382,7 @@
 	/* get from control */
 
 	while (retry--) {
-	    dr.requesttype = 0x80 | USB_TYPE_STANDARD | USB_RT_DEVICE;
+	    dr.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RT_DEVICE;
 	    dr.request = USB_REQ_GET_STATUS;
 	    dr.index = 0;
 	    dr.value = 0;
@@ -411,14 +410,14 @@
 
 	/* add interrupt transfer, marked for removal */
 	us->ip_wanted = 1;
-	irq_handle = us->pusb_dev->bus->op->request_irq(us->pusb_dev, 
-						    usb_rcvctrlpipe(us->pusb_dev, us->ep_int),
-						     pop_CBI_irq, 0, (void *)us);
-	if (!irq_handle) {
-	    US_DEBUGP("No interrupt for CBI\n");
+	us->irqpipe = usb_rcvctrlpipe(us->pusb_dev, us->ep_int);
+	result = us->pusb_dev->bus->op->request_irq(us->pusb_dev, us->irqpipe,
+						pop_CBI_irq, 0,
+						(void *)us, &us->irq_handle);
+	if (result) {
+	    US_DEBUGP("usb_scsi: usb_request_irq failed (0x%x), No interrupt for CBI\n", result);
 	    return DID_ABORT << 16;
 	}
-	us->irq_handle = irq_handle;
 
 	sleep_on(&us->ip_waitq);
 	if (us->ip_wanted) {
@@ -652,8 +651,9 @@
     struct us_data *prev = (struct us_data *)&us_list;
 
     if (us->irq_handle) {
-    	usb_release_irq(us->pusb_dev, us->irq_handle);
+    	usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe);
 	us->irq_handle = NULL;
+	us->irqpipe = 0;
     }
     if (us->filter)
 	us->filter->release(us->fdata);
@@ -893,7 +893,7 @@
 			us->srb->result = DID_OK << 16;
 		    else {
 			unsigned int savelen = us->srb->request_bufflen;
-			unsigned int saveallocation;
+			unsigned int saveallocation = 0;
 
 			switch (us->srb->cmnd[0]) {
 			case REQUEST_SENSE:
@@ -942,7 +942,7 @@
 			if (savelen != us->srb->request_bufflen &&
 			    us->srb->result == (DID_OK << 16)) {
 			    unsigned char *p = (unsigned char *)us->srb->request_buffer;
-			    unsigned int length;
+			    unsigned int length = 0;
 
 			    /* set correct length and retry */
 			    switch (us->srb->cmnd[0]) {
@@ -1195,7 +1195,7 @@
 
     for (i = 0; i < interface->bNumEndpoints; i++) { 
 	    if (interface->endpoint[i].bmAttributes == 0x02) {
-		    if (interface->endpoint[i].bEndpointAddress & 0x80)
+		    if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN)
 			    ss->ep_in = interface->endpoint[i].bEndpointAddress & 0x0f;
 		    else
 			    ss->ep_out = interface->endpoint[i].bEndpointAddress & 0x0f;
@@ -1288,7 +1288,7 @@
 	    dev->descriptor.idProduct == 0x0001) {
 	    devrequest dr;
 	    __u8 qstat[2];
-	    void *irq_handle;
+	    int result;
 
 	    /* shuttle E-USB */
 	    dr.requesttype = 0xC0;
@@ -1299,12 +1299,12 @@
 	    ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2);
 	    US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
 	    init_waitqueue_head(&ss->ip_waitq);
-	    irq_handle = ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, 
-						usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int),
-						pop_CBI_irq, 0, (void *)ss);
-	    if (!irq_handle)
+	    ss->irqpipe = usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int);
+	    result = ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, ss->irqpipe,
+						pop_CBI_irq, 0,
+						(void *)ss, &ss->irq_handle);
+	    if (result)
 	    	return -1;
-	    ss->irq_handle = irq_handle;
 	    interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*5);
 
 	} else if (ss->protocol == US_PR_CBI)
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/usb_scsi_debug.c linux/drivers/usb/usb_scsi_debug.c
--- v2.3.17/linux/drivers/usb/usb_scsi_debug.c	Sun Jun 20 11:43:42 1999
+++ linux/drivers/usb/usb_scsi_debug.c	Fri Sep 10 12:59:49 1999
@@ -15,8 +15,7 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include <linux/blk.h>
 #include "../scsi/scsi.h"
@@ -28,7 +27,7 @@
 
 void us_show_command(Scsi_Cmnd *srb)
 {
-    char *what;
+    char *what = NULL;
 
     switch (srb->cmnd[0]) {
     case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
diff -u --recursive --new-file v2.3.17/linux/drivers/usb/uss720.c linux/drivers/usb/uss720.c
--- v2.3.17/linux/drivers/usb/uss720.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/uss720.c	Fri Sep 10 12:59:49 1999
@@ -48,6 +48,7 @@
 struct parport_uss720_private {
 	struct usb_device *usbdev;
 	void *irqhandle;
+	unsigned int irqpipe;
         unsigned char reg[7];  /* USB registers */
 };
 
@@ -616,8 +617,15 @@
         endpoint = &interface->endpoint[2];
 	printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->bEndpointAddress, endpoint->bInterval);
 #if 0
-        priv->irqhandle = usb_request_irq(usbdev, usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress),
-					  uss720_irq, endpoint->bInterval, pp);
+	priv->irqpipe = usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress);
+	i = usb_request_irq(usbdev, priv->irqpipe,
+				  uss720_irq, endpoint->bInterval,
+				  pp, &priv->irqhandle);
+	if (i) {
+		printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i);
+		/* FIXME: undo some stuff and free some memory. */
+		return -1;
+	}
 #endif
         parport_proc_register(pp);
         parport_announce_port(pp);
@@ -632,7 +640,7 @@
 	struct parport_uss720_private *priv = pp->private_data;
 
 #if 0
-	usb_release_irq(usbdev, priv->irqhandle);
+	usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
 #endif
         usbdev->private = NULL;
         priv->usbdev = NULL;
diff -u --recursive --new-file v2.3.17/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.3.17/linux/drivers/video/Config.in	Thu Aug 26 13:05:39 1999
+++ linux/drivers/video/Config.in	Wed Sep  8 11:14:32 1999
@@ -105,6 +105,7 @@
       if [ "$ARCH" = "sparc" ]; then
         bool '  TCX (SS4/SS5 only) support' CONFIG_FB_TCX
 	bool '  CGfourteen (SX) support' CONFIG_FB_CGFOURTEEN
+        bool '  P9100 (Sparcbook 3 only) support' CONFIG_FB_P9100
       fi
       bool '  Leo (ZX) support' CONFIG_FB_LEO
     fi
@@ -184,6 +185,7 @@
 	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
          "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	 "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
+	 "$CONFIG_FB_P9100" = "y" -o \
 	 "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
       define_bool CONFIG_FBCON_CFB8 y
     else
@@ -198,6 +200,7 @@
 	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
            "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	   "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
+	   "$CONFIG_FB_P9100" = "m" -o \
 	   "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB8 m
       fi
diff -u --recursive --new-file v2.3.17/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.17/linux/drivers/video/Makefile	Thu Aug 26 13:05:39 1999
+++ linux/drivers/video/Makefile	Wed Sep  8 11:14:32 1999
@@ -281,6 +281,13 @@
     M_OBJS += cgfourteenfb.o
     endif
   endif
+  ifeq ($(CONFIG_FB_P9100),y)
+    L_OBJS += p9100fb.o
+  else
+    ifeq ($(CONFIG_FB_P9100),m)
+    M_OBJS += p9100fb.o
+    endif
+  endif
   ifeq ($(CONFIG_FB_LEO),y)
     L_OBJS += leofb.o
   else
@@ -331,6 +338,13 @@
     else
       ifeq ($(CONFIG_FB_CGFOURTEEN),m)
       M_OBJS += cgfourteenfb.o
+      endif
+    endif
+    ifeq ($(CONFIG_FB_P9100),y)
+      M_OBJS += p9100fb.o
+    else
+      ifeq ($(CONFIG_FB_P9100),m)
+      M_OBJS += p9100fb.o
       endif
     endif
     ifeq ($(CONFIG_FB_LEO),y)
diff -u --recursive --new-file v2.3.17/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.3.17/linux/drivers/video/atyfb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/atyfb.c	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.120 1999/08/30 10:12:18 davem Exp $
+/*  $Id: atyfb.c,v 1.122 1999/09/06 20:44:08 geert Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *	Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -89,8 +89,34 @@
  */
 #undef DEBUG
 
+/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
 
-#define GUI_RESERVE	0x00001000
+#define REF_FREQ_2595       1432  /*  14.33 MHz  (exact   14.31818) */
+#define REF_DIV_2595          46  /* really 43 on ICS 2595 !!!  */
+                                  /* ohne Prescaler */
+#define MAX_FREQ_2595      15938  /* 159.38 MHz  (really 170.486) */
+#define MIN_FREQ_2595       8000  /*  80.00 MHz  (        85.565) */
+                                  /* mit Prescaler 2, 4, 8 */
+#define ABS_MIN_FREQ_2595   1000  /*  10.00 MHz  (really  10.697) */
+#define N_ADJ_2595           257
+
+#define STOP_BITS_2595     0x1800
+
+
+#define MIN_N_408		2
+
+#define MIN_N_1703		6
+
+#define MIN_M		2
+#define MAX_M		30
+#define MIN_N		35
+#define MAX_N		255-8
+
+
+/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
+/*  - must be large enough to catch all GUI-Regs   */
+/*  - must be aligned to a PAGE boundary           */
+#define GUI_RESERVE	(1 * PAGE_SIZE)
 
 
 #ifndef __powerpc__
@@ -126,6 +152,14 @@
     u8 n;
 };
 
+struct pll_18818
+{
+    u32 program_bits;
+    u32 locationAddr;
+    u32 period_in_ps;
+    u32 post_divider;
+};
+
 struct pll_ct {
     u8 pll_ref_div;
     u8 pll_gen_cntl;
@@ -150,6 +184,7 @@
     union {
 	struct pll_gx gx;
 	struct pll_ct ct;
+	struct pll_18818 ics2595;
     } pll;
     u32 accel_flags;
 };
@@ -196,6 +231,7 @@
     unsigned long ati_regbase;
     unsigned long frame_buffer_phys;
     unsigned long frame_buffer;
+    unsigned long clk_wr_offset;
     struct pci_mmap_map *mmap_map;
     struct aty_cursor *cursor;
     struct aty_cmap_regs *aty_cmap_regs;
@@ -213,6 +249,7 @@
     u8 bus_type;
     u8 ram_type;
     u8 dac_type;
+    u8 dac_subtype;
     u8 clk_type;
     u8 mem_refresh_rate;
     struct display disp;
@@ -329,6 +366,7 @@
 
 static void reset_engine(const struct fb_info_aty *info);
 static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info);
+
 static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
 static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
 static u8 aty_ld_pll(int offset, const struct fb_info_aty *info);
@@ -342,7 +380,37 @@
 			   struct fb_var_screeninfo *var);
 static void aty_set_pll_gx(const struct fb_info_aty *info,
 			   const struct pll_gx *pll);
-static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll);
+
+static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp,
+				  u32 AccelMode);
+static int aty_set_dac_ATT21C498(const struct fb_info_aty *info,
+				 const struct pll_18818 *pll, u32 bpp);
+void aty_dac_waste4(const struct fb_info_aty *info);
+
+static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll);
+static u32 aty_pll_18818_to_var(const struct pll_18818 *pll);
+static void aty_set_pll18818(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll);
+
+static void aty_StrobeClock(const struct fb_info_aty *info);
+
+static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info);
+
+static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll);
+static u32 aty_pll_408_to_var(const struct pll_18818 *pll);
+static void aty_set_pll_408(const struct fb_info_aty *info,
+			    const struct pll_18818 *pll);
+
+static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll);
+static u32 aty_pll_1703_to_var(const struct pll_18818 *pll);
+static void aty_set_pll_1703(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll);
+
+static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll);
+static u32 aty_pll_8398_to_var(const struct pll_18818 *pll);
+static void aty_set_pll_8398(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll);
+
 static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll);
 static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
 			     const struct fb_info_aty *info);
@@ -1193,6 +1261,124 @@
     return 0;
 }
 
+
+static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp,
+				  u32 AccelMode)
+{
+    u32 gModeReg, devSetupRegA, temp, mask;
+
+    gModeReg = 0;
+    devSetupRegA = 0;
+    
+    switch (bpp) {
+	case 8:
+	    gModeReg = 0x83;
+	    devSetupRegA = 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */;
+	    break;
+	case 15:
+	    gModeReg = 0xA0;
+	    devSetupRegA = 0x60;
+	    break;
+	case 16:
+	    gModeReg = 0xA1;
+	    devSetupRegA = 0x60;
+	    break;
+	case 24:
+	    gModeReg = 0xC0;
+	    devSetupRegA = 0x60;
+	    break;
+	case 32:
+	    gModeReg = 0xE3;
+	    devSetupRegA = 0x60;
+	    break;
+    }
+
+    if (!AccelMode) {
+	gModeReg = 0x80;
+	devSetupRegA = 0x61;
+    }
+
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
+
+    aty_st_8(DAC_REGS + 2, 0x1D, info);
+    aty_st_8(DAC_REGS + 3, gModeReg, info);
+    aty_st_8(DAC_REGS, 0x02, info);
+
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
+
+    if (info->total_vram < MEM_SIZE_1M)
+	mask = 0x04;
+    else if (info->total_vram == MEM_SIZE_1M)
+	mask = 0x08;
+    else
+	mask = 0x0C;
+
+    /* The following assumes that the BIOS has correctly set R7 of the
+     * Device Setup Register A at boot time.
+     */
+#define A860_DELAY_L	0x80
+
+    temp = aty_ld_8(DAC_REGS, info);
+    aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), info);
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info);
+
+    return 0;
+}
+
+static int aty_set_dac_ATT21C498(const struct fb_info_aty *info,
+				 const struct pll_18818 *pll, u32 bpp)
+{
+    u32 dotClock;
+    int muxmode = 0;
+    int DACMask = 0;
+
+    dotClock = 100000000 / pll->period_in_ps;
+
+    switch (bpp) {
+	case 8:
+	    if (dotClock > 8000) {
+		DACMask = 0x24;
+		muxmode = 1;
+	    } else
+		DACMask = 0x04;
+	    break;
+	case 15:
+	    DACMask = 0x16;
+	    break;
+	case 16:
+	    DACMask = 0x36;
+	    break;
+	case 24:
+	    DACMask = 0xE6;
+	    break;
+	case 32:
+	    DACMask = 0xE6;
+	    break;
+    }
+
+    if (1 /* info->mach64DAC8Bit */)
+	DACMask |= 0x02;
+
+    aty_dac_waste4(info);
+    aty_st_8(DAC_REGS + 2, DACMask, info);
+
+    return muxmode;
+}
+
+void aty_dac_waste4(const struct fb_info_aty *info)
+{
+  (void)aty_ld_8(DAC_REGS, info);
+
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+}
+
+
 static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp)
 {
     static struct {
@@ -1390,60 +1576,477 @@
     }
 }
 
-static int aty_var_to_pll_18818(u32 vclk_per, struct pll_gx *pll)
+
+static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll)
 {
-    /*
-     *  FIXME: use real calculations instead of using fixed values from the old
-     *	       driver
-     */
-    static struct {
-	u32 ps_lim;	/* pixclock period rounding limit (arbitrary) */
-	u8 mode;	/* (prescsaler << 4) | Select */
-	u8 prog;	/* ref_div_count */
-    } ATI18818_clocks[] = {
-	{  7500, 0x0B, 1 },	/*  7407.4 ps = 135.00 MHz */
-	{  9000, 0x0A, 1 },	/*  7936.5 ps = 126.00 MHz */
-	{ 11000, 0x09, 1 },	/* 10000.0 ps = 100.00 MHz */
-	{ 12800, 0x0D, 1 },	/* 12500.0 ps =  80.00 MHz */
-	{ 13500, 0x0E, 1 },	/* 13333.3 ps =  75.00 MHz */
-/*	{ 14000, 0x03, 2 },*/	/* 13888.8 ps =  72.00 MHz */
-	{ 15000, 0x1B, 1 },	/* 14814.8 ps =  67.50 MHz */
-	{ 15500, 0x0F, 1 },	/* 15384.6 ps =  65.00 MHz */
-	{ 16000, 0x1A, 1 },	/* 15873.0 ps =  63.00 MHz */
-/*	{ 16000, 0x02, 2 },*/	/* 15873.0 ps =  63.00 MHz */
-/*	{ 18000, 0x01, 2 },*/	/* 17655.4 ps =  56.64 MHz */
-/*	{ 19900, 0x00, 2 },*/	/* 19860.9 ps =  50.35 MHz */
-	{ 20000, 0x07, 1 },	/* 20000.0 ps =  50.00 MHz */
-	{ 20300, 0x06, 1 },	/* 20202.0 ps =  49.50 MHz */
-	{ 22500, 0x05, 1 },	/* 22271.2 ps =  44.90 MHz */
-	{ 25000, 0x04, 1 },	/* 25000.0 ps =  40.00 MHz */
-/*	{ 28000, 0x03, 1 },*/	/* 27777.8 ps =  36.00 MHz */
-	{ 30000, 0x2B, 1 },	/* 29629,6 ps =  33.75 MHz */
-	{ 31000, 0x1F, 1 },	/* 30769.2 ps =  32.50 MHz */
-	{ 32000, 0x2A, 1 },	/* 31746.0 ps =  31.50 MHz */
-/*	{ 32000, 0x02, 1 },*/	/* 31746.0 ps =  31.50 MHz */
-/*	{ 36000, 0x01, 1 },*/	/* 35310.7 ps =  28.32 MHz */
-/*	{ 39900, 0x00, 1 },*/	/* 39714.1 ps =  25.18 MHz */
-	{ 40000, 0x17, 1 },	/* 40000.0 ps =  25.00 MHz */
-	{ 40600, 0x16, 1 },	/* 40404.0 ps =  24.75 MHz */
-	{ 45000, 0x15, 1 },	/* 44543.4 ps =  22.45 MHz */
-	{ 50000, 0x14, 1 },	/* 50000.0 ps =  20.00 MHz */
-/*	{ 56000, 0x13, 1 },*/	/* 55555.5 ps =  18.00 MHz */
-	{ 62000, 0x2F, 1 },	/* 61538.8 ps =  16.25 MHz */
-/*	{ 64000, 0x12, 1 },*/	/* 63492.0 ps =  15.75 MHz */
-    };
-    int set;
+    u32 MHz100;		/* in 0.01 MHz */
+    u32 program_bits;
+    u32 post_divider;
 
-    for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks);
-	 set++)
-	if (vclk_per <= ATI18818_clocks[set].ps_lim) {
-	    pll->m = ATI18818_clocks[set].mode;
-	    pll->n = ATI18818_clocks[set].prog;
-	    return 0;
+    /* Calculate the programming word */
+    MHz100 = 100000000 / period_in_ps;
+    
+    program_bits = -1;
+    post_divider = 1;
+
+    if (MHz100 > MAX_FREQ_2595) {
+	MHz100 = MAX_FREQ_2595;
+	return -EINVAL;
+    } else if (MHz100 < ABS_MIN_FREQ_2595) {
+	program_bits = 0;	/* MHz100 = 257 */
+	return -EINVAL;
+    } else {
+	while (MHz100 < MIN_FREQ_2595) {
+	    MHz100 *= 2;
+	    post_divider *= 2;
 	}
-    return -EINVAL;
+    }
+    MHz100 *= 1000;
+    MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
+
+    MHz100 += 500;    /* + 0.5 round */
+    MHz100 /= 1000;
+
+    if (program_bits == -1) {
+	program_bits = MHz100 - N_ADJ_2595;
+	switch (post_divider) {
+	    case 1:
+		program_bits |= 0x0600;
+		break;
+	    case 2:
+		program_bits |= 0x0400;
+		break;
+	    case 4:
+		program_bits |= 0x0200;
+		break;
+	    case 8:
+	    default:
+		break;
+	}
+    }
+
+    program_bits |= STOP_BITS_2595;
+
+    pll->program_bits = program_bits;
+    pll->locationAddr = 0;
+    pll->post_divider = post_divider;
+    pll->period_in_ps = period_in_ps;
+
+    return 0;
 }
 
+static u32 aty_pll_18818_to_var(const struct pll_18818 *pll)
+{
+    return(pll->period_in_ps);  /* default for now */
+}
+
+static void aty_set_pll18818(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    u32 i;
+
+    u8 old_clock_cntl;
+    u8 old_crtc_ext_disp;
+
+    old_clock_cntl = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    udelay(15000); /* delay for 50 (15) ms */
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program the clock chip */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);  /* Strobe = 0 */
+    aty_StrobeClock(info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info);  /* Strobe = 0 */
+    aty_StrobeClock(info);
+
+    aty_ICS2595_put1bit(1, info);    /* Send start bits */
+    aty_ICS2595_put1bit(0, info);    /* Start bit */
+    aty_ICS2595_put1bit(0, info);    /* Read / ~Write */
+
+    for (i = 0; i < 5; i++) {	/* Location 0..4 */
+	aty_ICS2595_put1bit(locationAddr & 1, info);
+	locationAddr >>= 1;
+    }
+
+    for (i = 0; i < 8 + 1 + 2 + 2; i++) {
+	aty_ICS2595_put1bit(program_bits & 1, info);
+	program_bits >>= 1;
+    }
+
+    udelay(1000); /* delay for 1 ms */
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE,
+	     info);
+
+    udelay(50000); /* delay for 50 (15) ms */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset,
+	     ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info);
+   
+    return;
+}
+
+
+static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll)
+{
+    u32 mhz100;		/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u32 temp, tempB;
+    u16 remainder, preRemainder;
+    short divider = 0, tempA;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / period_in_ps;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+    
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xFF;
+    else {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	while (mhz100 < (mach64MinFreq << 3)) {
+	    mhz100 <<= 1;
+	    divider += 0x40;
+	}
+
+	temp = (unsigned int)mhz100;
+	temp = (unsigned int)(temp * (MIN_N_408 + 2));
+	temp -= ((short)(mach64RefFreq << 1));
+
+	tempA = MIN_N_408;
+	preRemainder = 0xFFFF;
+
+	do {
+	    tempB = temp;
+	    remainder = tempB % mach64RefFreq;
+	    tempB = tempB / mach64RefFreq;
+	    if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) {
+		preRemainder = remainder;
+		divider &= ~0x3f;
+		divider |= tempA;
+		divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8);
+	    }
+	    temp += mhz100;
+	    tempA++;
+	} while(tempA <= 32);
+
+	program_bits = divider;
+    }
+
+    pll->program_bits = program_bits;
+    pll->locationAddr = 0;
+    pll->post_divider = divider;	/* fuer nix */
+    pll->period_in_ps = period_in_ps;
+
+    return 0;
+}
+
+static u32 aty_pll_408_to_var(const struct pll_18818 *pll)
+{
+    return(pll->period_in_ps);  /* default for now */
+}
+
+static void aty_set_pll_408(const struct fb_info_aty *info,
+			    const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    u8 tmpA, tmpB, tmpC;
+    char old_crtc_ext_disp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program clock */
+    aty_dac_waste4(info);
+    tmpB = aty_ld_8(DAC_REGS + 2, info) | 1;
+    aty_dac_waste4(info);
+    aty_st_8(DAC_REGS + 2, tmpB, info);
+
+    tmpA = tmpB;
+    tmpC = tmpA;
+    tmpA |= 8;
+    tmpB = 1;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    udelay(400); /* delay for 400 us */
+
+    locationAddr = (locationAddr << 2) + 0x40;
+    tmpB = locationAddr;
+    tmpA = program_bits >> 8;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    tmpB = locationAddr + 1;
+    tmpA = (u8)program_bits;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    tmpB = locationAddr + 2;
+    tmpA = 0x77;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    udelay(400); /* delay for 400 us */
+    tmpA = tmpC & (~(1 | 8));
+    tmpB = 1;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+
+static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll)
+{
+    u32 mhz100;			/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u32 temp, tempB;
+    u16 remainder, preRemainder;
+    short divider = 0, tempA;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / period_in_ps;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+    
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xE0;
+    else {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	divider = 0;
+	while (mhz100 < (mach64MinFreq << 3)) {
+	    mhz100 <<= 1;
+	    divider += 0x20;
+	}
+
+	temp = (unsigned int)(mhz100);
+	temp = (unsigned int)(temp * (MIN_N_1703 + 2));
+	temp -= (short)(mach64RefFreq << 1);
+
+	tempA = MIN_N_1703;
+	preRemainder = 0xffff;
+
+	do {
+	    tempB = temp;
+	    remainder = tempB % mach64RefFreq;
+	    tempB = tempB / mach64RefFreq;
+
+	    if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) {
+		preRemainder = remainder;
+		divider &= ~0x1f;
+		divider |= tempA;
+		divider = (divider & 0x00ff) + ((tempB & 0xff) << 8);
+	    }
+
+	    temp += mhz100;
+	    tempA++;
+	} while (tempA <= (MIN_N_1703 << 1));
+
+	program_bits = divider;
+    }
+
+      pll->program_bits = program_bits;
+      pll->locationAddr = 0;
+      pll->post_divider = divider;  /* fuer nix */
+      pll->period_in_ps = period_in_ps;
+
+      return 0;
+}
+
+static u32 aty_pll_1703_to_var(const struct pll_18818 *pll)
+{
+    return(pll->period_in_ps);  /* default for now */
+}
+
+static void aty_set_pll_1703(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    char old_crtc_ext_disp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program clock */
+    aty_dac_waste4(info);
+
+    (void)aty_ld_8(DAC_REGS + 2, info);
+    aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info);
+    aty_st_8(DAC_REGS+2, 0, info);
+    aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info);
+    aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+
+static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll)
+{
+
+    u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
+
+    u32 mhz100;				/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u16 m, n, k=0, save_m, save_n, twoToKth;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / period_in_ps;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+    
+    save_m = 0;
+    save_n = 0;
+
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xE0;
+    else
+    {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	longMHz100 = mhz100 * 256 / 100;   /* 8 bit scale this */
+
+	while (mhz100 < (mach64MinFreq << 3))
+        {
+	    mhz100 <<= 1;
+	    k++;
+	}
+
+	twoToKth = 1 << k;
+	diff = 0;
+	preDiff = 0xFFFFFFFF;
+
+	for (m = MIN_M; m <= MAX_M; m++)
+        {
+	    for (n = MIN_N; n <= MAX_N; n++)
+            {
+		tempA = (14.31818 * 65536);
+		tempA *= (n + 8);  /* 43..256 */
+		tempB = twoToKth * 256;
+		tempB *= (m + 2);  /* 4..32 */
+		fOut = tempA / tempB;  /* 8 bit scale */
+
+		if (longMHz100 > fOut)
+		    diff = longMHz100 - fOut;
+		else
+		    diff = fOut - longMHz100;
+
+		if (diff < preDiff)
+                {
+		    save_m = m;
+		    save_n = n;
+		    preDiff = diff;
+		}
+	    }
+	}
+
+	program_bits = (k << 6) + (save_m) + (save_n << 8);
+    }
+
+    pll->program_bits = program_bits;
+    pll->locationAddr = 0;
+    pll->post_divider = 0;
+    pll->period_in_ps = period_in_ps;
+
+    return 0;
+}
+
+static u32 aty_pll_8398_to_var(const struct pll_18818 *pll)
+{
+    return(pll->period_in_ps);  /* default for now */
+}
+
+static void aty_set_pll_8398(const struct fb_info_aty *info,
+			     const struct pll_18818 *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    char old_crtc_ext_disp;
+    char tmp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->program_bits;
+    locationAddr = pll->locationAddr;
+
+    /* Program clock */
+    tmp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
+
+    aty_st_8(DAC_REGS, locationAddr, info);
+    aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info);
+    aty_st_8(DAC_REGS+1, (program_bits & 0xff), info);
+
+    tmp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+
 static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll)
 {
     /*
@@ -1474,7 +2077,42 @@
     return -EINVAL;
 }
 
-    /* FIXME: ATI18818?? */
+
+static void aty_StrobeClock(const struct fb_info_aty *info)
+{
+    u8 tmp;
+
+    udelay(26);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info);
+
+    return;
+}
+
+
+static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info)
+{
+    u8 tmp;
+
+    data &= 0x01;
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2),
+	     info);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info);
+
+    aty_StrobeClock(info);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info);
+
+    aty_StrobeClock(info);
+
+    return;
+}
+
 
 static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
 			     const struct fb_info_aty *info)
@@ -1720,27 +2358,76 @@
 			  struct fb_info_aty *info)
 {
     u32 i;
+    int accelmode;
+    int muxmode;
+    u8 tmp;
+    
+    accelmode = par->accel_flags;  /* hack */
 
     info->current_par = *par;
 
     if (info->blitter_may_be_busy)
 	wait_for_idle(info);
+    tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
     aty_set_crtc(info, &par->crtc);
-    aty_st_8(CLOCK_CNTL, 0, info);
-    aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
+					/* better call aty_StrobeClock ?? */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info);
 
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
-	switch (info->dac_type) {
+	switch (info->dac_subtype) {
 	    case DAC_IBMRGB514:
 		aty_set_dac_514(info, par->crtc.bpp);
 		break;
 	    case DAC_ATI68860_B:
-		/* FIXME */
+	    case DAC_ATI68860_C:
+		muxmode = aty_set_dac_ATI68860_B(info, par->crtc.bpp,
+						 accelmode);
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x47052100, info);
+		break;
+	    case DAC_ATT20C408:
+		muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595,
+						par->crtc.bpp);
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x00072000, info);
+		break;
+	    case DAC_ATT21C498:
+		muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595,
+						par->crtc.bpp);
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x00072000, info);
 		break;
-	}
-	aty_set_pll_gx(info, &par->pll.gx);
+	    default:
+		printk(" atyfb_set_par: DAC type not implemented yet!\n");
+		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+		aty_st_le32(DAC_CNTL, 0x47052100, info);
+	/* new in 2.2.3p1 from Geert. ???????? */
 	aty_st_le32(BUS_CNTL, 0x590e10ff, info);
 	aty_st_le32(DAC_CNTL, 0x47012100, info);
+		break;
+	}
+
+	switch (info->clk_type) {
+	    case CLK_ATI18818_1:
+		aty_set_pll18818(info, &par->pll.ics2595);
+		break;
+	    case CLK_STG1703:
+		aty_set_pll_1703(info, &par->pll.ics2595);
+		break;
+	    case CLK_CH8398:
+		aty_set_pll_8398(info, &par->pll.ics2595);
+		break;
+	    case CLK_ATT20C408:
+		aty_set_pll_408(info, &par->pll.ics2595);
+		break;
+	    case CLK_IBMRGB514:
+		aty_set_pll_gx(info, &par->pll.gx);
+		break;
+	    default:
+		printk(" atyfb_set_par: CLK type not implemented yet!");
+		break;
+	}
 
 	/* Don't forget MEM_CNTL */
 	i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff;
@@ -1828,7 +2515,16 @@
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
 	switch (info->clk_type) {
 	    case CLK_ATI18818_1:
-		err = aty_var_to_pll_18818(var->pixclock, &par->pll.gx);
+		err = aty_var_to_pll_18818(var->pixclock, &par->pll.ics2595);
+		break;
+	    case CLK_STG1703:
+		err = aty_var_to_pll_1703(var->pixclock, &par->pll.ics2595);
+		break;
+	    case CLK_CH8398:
+		err = aty_var_to_pll_8398(var->pixclock, &par->pll.ics2595);
+		break;
+	    case CLK_ATT20C408:
+		err = aty_var_to_pll_408(var->pixclock, &par->pll.ics2595);
 		break;
 	    case CLK_IBMRGB514:
 		err = aty_var_to_pll_514(var->pixclock, &par->pll.gx);
@@ -1864,7 +2560,23 @@
     if ((err = aty_crtc_to_var(&par->crtc, var)))
 	return err;
     if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
-	var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info);
+	switch (info->clk_type) {
+	    case CLK_ATI18818_1:
+		var->pixclock = aty_pll_18818_to_var(&par->pll.ics2595);
+		break;
+	    case CLK_STG1703:
+		var->pixclock = aty_pll_1703_to_var(&par->pll.ics2595);
+		break;
+	    case CLK_CH8398:
+		var->pixclock = aty_pll_8398_to_var(&par->pll.ics2595);
+		break;
+	    case CLK_ATT20C408:
+		var->pixclock = aty_pll_408_to_var(&par->pll.ics2595);
+		break;
+	    case CLK_IBMRGB514:
+	        var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info);
+		break;
+	}
     else
 	var->pixclock = aty_pll_ct_to_var(&par->pll.ct, info);
 
@@ -2234,7 +2946,9 @@
 static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		       u_long arg, int con, struct fb_info *info2)
 {
+#if defined(__sparc__) || defined(DEBUG)
     struct fb_info_aty *info = (struct fb_info_aty *)info2;
+#endif /* __sparc__ || DEBUG */
 #ifdef __sparc__
     struct fbtype fbtyp;
     struct display *disp;
@@ -2540,6 +3254,7 @@
     for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
 	if (aty_features[j].chip_type == Gx) {
 	    chipname = aty_features[j].name;
+	    info->dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07;
 	    break;
 	}
     if (!chipname) {
@@ -2553,10 +3268,16 @@
 	ramname = aty_gx_ram[info->ram_type];
 	/* FIXME: clockchip/RAMDAC probing? */
 #ifdef CONFIG_ATARI
-	info->dac_type = DAC_ATI68860_B;
 	info->clk_type = CLK_ATI18818_1;
+	info->dac_type = (aty_ld_le32(CONFIG_STAT0, info) >> 9) & 0x07;
+	if (info->dac_type == 0x07)
+	    info->dac_subtype = DAC_ATT20C408;
+	else
+	    info->dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) |
+				info->dac_type;
 #else
 	info->dac_type = DAC_IBMRGB514;
+	info->dac_subtype = DAC_IBMRGB514;
 	info->clk_type = CLK_IBMRGB514;
 #endif
 	/* FIXME */
@@ -2567,6 +3288,7 @@
 	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
 	ramname = aty_ct_ram[info->ram_type];
 	info->dac_type = DAC_INTERNAL;
+	info->dac_subtype = DAC_INTERNAL;
 	info->clk_type = CLK_INTERNAL;
 	if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
 	    pll = 135;
@@ -3175,7 +3897,9 @@
 #endif /* __sparc__ */
 	}
     }
+
 #elif defined(CONFIG_ATARI)
+  u32   clock_r;
     int m64_num;
     struct fb_info_aty *info;
 
@@ -3199,9 +3923,27 @@
 	 *  kernel address space.
 	 */
 	info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]);
-	info->frame_buffer_phys = info->frame_buffer;
+	info->frame_buffer_phys = info->frame_buffer;  /* Fake! */
 	info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul;
-	info->ati_regbase_phys = info->ati_regbase;
+	info->ati_regbase_phys = info->ati_regbase;  /* Fake! */
+
+	aty_st_le32(CLOCK_CNTL, 0x12345678, info);
+	clock_r = aty_ld_le32(CLOCK_CNTL, info);
+
+	switch (clock_r & 0x003F) {
+	    case 0x12:
+		info->clk_wr_offset = 3;  /*  */
+		break;
+	    case 0x34:
+		info->clk_wr_offset = 2;  /* Medusa ST-IO ISA Adapter etc. */
+		break;
+	    case 0x16:
+		info->clk_wr_offset = 1;  /*  */
+		break;
+	    case 0x38:
+		info->clk_wr_offset = 0;  /* Panther 1 ISA Adapter (Gerald) */
+		break;
+	}
 
 	if (!aty_init(info, "ISA bus")) {
 	    kfree(info);
@@ -3209,7 +3951,7 @@
 	    return -ENXIO;
 	}
     }
-#endif
+#endif /* CONFIG_ATARI */
     return 0;
 }
 
diff -u --recursive --new-file v2.3.17/linux/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- v2.3.17/linux/drivers/video/clgenfb.c	Thu Aug 26 13:05:40 1999
+++ linux/drivers/video/clgenfb.c	Fri Sep 10 11:12:16 1999
@@ -31,7 +31,7 @@
  *
  */
 
-#define CLGEN_VERSION "1.9.4.3"
+#define CLGEN_VERSION "1.9.4.4"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -44,6 +44,7 @@
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/init.h>
+#include <linux/selection.h>
 #include <asm/pgtable.h>
 #include <asm/delay.h>
 #include <asm/io.h>
@@ -70,6 +71,13 @@
 #include "clgenfb.h"
 #include "vga.h"
 
+
+/*****************************************************************
+ *
+ * compatibility with older kernel versions
+ *
+ */
+
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
@@ -78,6 +86,18 @@
 #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
 #endif
 
+#ifndef PCI_DEVICE_ID_CIRRUS_5462
+#define PCI_DEVICE_ID_CIRRUS_5462      0x00d0
+#endif
+
+
+
+
+/*****************************************************************
+ *
+ * debugging and utility macros
+ *
+ */
 
 /* enable debug output? */
 /* #define CLGEN_DEBUG 1 */
@@ -120,6 +140,14 @@
 #define MAX_NUM_BOARDS 7
 
 
+
+
+/*****************************************************************
+ *
+ * chipset information
+ *
+ */
+
 /* board types */
 typedef enum {
 	BT_NONE = 0,
@@ -130,6 +158,7 @@
 	BT_PICASSO4,	/* GD5446 */
 	BT_ALPINE,	/* GD543x/4x */
 	BT_GD5480,
+	BT_LAGUNA,	/* GD546x */
 } clgen_board_t;
 
 
@@ -149,61 +178,116 @@
 				 * by this value */
 	char *name;		/* ASCII name of chipset */
 	long maxclock;		/* maximum video clock */
-	unsigned write_sr1f : 1; /* write SR1F during init_vgachip() */
+	unsigned init_sr07 : 1;	/* init SR07 during init_vgachip() */
+	unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
 	unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
-	unsigned char sr07;	/* SR07 VGA register value */
-	unsigned char sr1f;	/* SR1F VGA register value */
+
+	/* initial SR07 value, then for each mode */
+	unsigned char sr07;
+	unsigned char sr07_1bpp;
+	unsigned char sr07_1bpp_mux;
+	unsigned char sr07_8bpp;
+	unsigned char sr07_8bpp_mux;
+
+	unsigned char sr1f;	/* SR1F VGA initial register value */
 } clgen_board_info[] = {
 	{ BT_NONE, }, /* dummy record */
 	{ BT_SD64,
 		"CL SD64",
 		140000,		/* the SD64/P4 have a higher max. videoclock */
-		TRUE,		
-		TRUE,		
-		0xf0,		
+		TRUE,
+		TRUE,
+		TRUE,
+		0xF0,		
+		0xF0,
+		0,		/* unused, does not multiplex */
+		0xF1,
+		0,		/* unused, does not multiplex */
 		0x20 },		
 	{ BT_PICCOLO,
 		"CL Piccolo",
 		90000,		
 		TRUE,
+		TRUE,
 		FALSE,
 		0x80,
+		0x80,
+		0,		/* unused, does not multiplex */
+		0x81,
+		0,		/* unused, does not multiplex */
 		0x22 },
 	{ BT_PICASSO,
 		"CL Picasso",
 		90000,
 		TRUE,
+		TRUE,
 		FALSE,
 		0x20,
+		0x20,
+		0,		/* unused, does not multiplex */
+		0x21,
+		0,		/* unused, does not multiplex */
 		0x22 },
 	{ BT_SPECTRUM,
 		"CL Spectrum",
 		90000,
 		TRUE,
+		TRUE,
 		FALSE,
 		0x80,
+		0x80,
+		0,		/* unused, does not multiplex */
+		0x81,
+		0,		/* unused, does not multiplex */
 		0x22 },
 	{ BT_PICASSO4,
 		"CL Picasso4",
 		140000,		/* the SD64/P4 have a higher max. videoclock */
+		TRUE,
 		FALSE,
 		TRUE,
 		0x20,
+		0x20,
+		0,		/* unused, does not multiplex */
+		0x21,
+		0,		/* unused, does not multiplex */
 		0 },
 	{ BT_ALPINE,
 		"CL Alpine",
 		110000,		/* 135100 for some, 85500 for others */
 		TRUE,
 		TRUE,
+		TRUE,
 		0xA0,
+		0xA1,
+		0xA7,
+		0xA1,
+		0xA7,
 		0x1C },
 	{ BT_GD5480,
 		"CL GD5480",
 		90000,
 		TRUE,
 		TRUE,
+		TRUE,
 		0x10,
+		0x11,
+		0,		/* unused, does not multiplex */
+		0x11,
+		0,		/* unused, does not multiplex */
 		0x1C },
+	{ BT_LAGUNA,
+		"CL Laguna",
+		135100,
+		FALSE,
+		FALSE,
+		TRUE,
+		0,		/* unused */
+		0,		/* unused */
+		0,		/* unused */
+		0,		/* unused */
+		0,		/* unused */
+		0 },		/* unused */
 };
 
 
@@ -212,14 +296,18 @@
  * order in which we do it */
 static const struct {
 	clgen_board_t btype;
+	const char *nameOverride; /* XXX unused... for now */
 	unsigned short device;
 } clgen_pci_probe_list[] __initdata = {
-	{ BT_ALPINE, PCI_DEVICE_ID_CIRRUS_5436 },
-	{ BT_ALPINE, PCI_DEVICE_ID_CIRRUS_5434_8 },
-	{ BT_ALPINE, PCI_DEVICE_ID_CIRRUS_5434_4 },
-	{ BT_ALPINE, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
-	{ BT_GD5480, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
-	{ BT_PICASSO4, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
+	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5436 },
+	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_8 },
+	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 },
+	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
+	{ BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
+	{ BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
+	{ BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 },
+	{ BT_LAGUNA, "CL Laguna 3D", PCI_DEVICE_ID_CIRRUS_5464 },
+	{ BT_LAGUNA, "CL Laguna 3DA", PCI_DEVICE_ID_CIRRUS_5465 },
 };
 #endif /* CONFIG_PCI */
 
@@ -310,6 +398,9 @@
 	unsigned long fbregs_phys;
 
 	struct clgenfb_par currentmode;
+
+	struct { u8 red, green, blue, pad; } palette[256];
+
 	union {
 #ifdef FBCON_HAS_CFB16
 		u16 cfb16[16];
@@ -550,9 +641,11 @@
 static void WClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char red,
 		   unsigned char green,
 		   unsigned char blue);
+#if 0
 static void RClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char *red,
 		   unsigned char *green,
 		   unsigned char *blue);
+#endif
 static void clgen_WaitBLT (caddr_t regbase);
 static void clgen_BitBLT (caddr_t regbase, u_short curx, u_short cury,
 			  u_short destx, u_short desty,
@@ -1071,12 +1164,15 @@
 	int offset = 0;
 	struct clgenfb_par *_par = (struct clgenfb_par *) par;
 	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
+	const struct clgen_board_info_rec *bi;
 
 	DPRINTK ("ENTER\n");
 	DPRINTK ("Requested mode: %dx%dx%d\n",
 	       _par->var.xres, _par->var.yres, _par->var.bits_per_pixel);
 	DPRINTK ("pixclock: %d\n", _par->var.pixclock);
 
+	bi = &clgen_board_info[fb_info->btype];
+
 
 	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
 	vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
@@ -1214,23 +1310,53 @@
 	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_START, 0);	/* text cursor on and start line */
 	vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_END, 31);	/* text cursor end line */
 
+	/******************************************************
+	 *
+	 * 1 bpp
+	 *
+	 */
+	
 	/* programming for different color depths */
 	if (_par->var.bits_per_pixel == 1) {
 		DPRINTK ("clgen: preparing for 1 bit deep display\n");
 		vga_wgfx (fb_info->regs, VGA_GFX_MODE, 0);	/* mode register */
 
+		/* SR07 */
+		switch (fb_info->btype) {
+		case BT_SD64:
+		case BT_PICCOLO:
+		case BT_PICASSO:
+		case BT_SPECTRUM:
+		case BT_PICASSO4:
+		case BT_ALPINE:
+		case BT_GD5480:
+			DPRINTK (" (for GD54xx)\n");
+			vga_wseq (fb_info->regs, CL_SEQR7,
+				  _par->multiplexing ?
+				  	bi->sr07_1bpp_mux : bi->sr07_1bpp);
+			break;
+
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (fb_info->regs, CL_SEQR7,
+				vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
+			break;
+			
+		default:
+			printk (KERN_WARNING "clgen: unknown Board\n");
+			break;
+		}
+
 		/* Extended Sequencer Mode */
 		switch (fb_info->btype) {
 		case BT_SD64:
 			/* setting the SEQRF on SD64 is not necessary (only during init) */
 			DPRINTK ("(for SD64)\n");
-			vga_wseq (fb_info->regs, CL_SEQR7, 0xf0);
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x1a);		/*  MCLK select */
 			break;
 
 		case BT_PICCOLO:
 			DPRINTK ("(for Piccolo)\n");
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x80);
 /* ### ueberall 0x22? */
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ##vorher 1c MCLK select */
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
@@ -1238,41 +1364,25 @@
 
 		case BT_PICASSO:
 			DPRINTK ("(for Picasso)\n");
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x20);
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ##vorher 22 MCLK select */
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xd0);	/* ## vorher d0 avoid FIFO underruns..? */
 			break;
 
 		case BT_SPECTRUM:
 			DPRINTK ("(for Spectrum)\n");
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x80);
 /* ### ueberall 0x22? */
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ##vorher 1c MCLK select */
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* evtl d0? avoid FIFO underruns..? */
 			break;
 
 		case BT_PICASSO4:
-			DPRINTK ("(for Picasso 4)\n");
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x20);
-/*                      vga_wseq(fb_info->regs, CL_SEQR1F, 0x1c); */
-/* SEQRF not being set here...  vga_wseq(fb_info->regs, CL_SEQRF, 0xd0); */
-			break;
-
 		case BT_ALPINE:
-			DPRINTK (" (for GD543x)\n");
-			if (_par->multiplexing)
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
-			else
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa1);
-			/* We already set SRF and SR1F */
-			break;
-
 		case BT_GD5480:
-			DPRINTK (" (for GD5480)\n");
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x11);
-			/* We already set SRF and SR1F */
+		case BT_LAGUNA:
+			DPRINTK (" (for GD54xx)\n");
+			/* do nothing */
 			break;
-
+			
 		default:
 			printk (KERN_WARNING "clgen: unknown Board\n");
 			break;
@@ -1286,54 +1396,78 @@
 		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x06);	/* memory mode: odd/even, ext. memory */
 		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0x01);	/* plane mask: only write to first plane */
 		offset = _par->var.xres_virtual / 16;
-	} else if (_par->var.bits_per_pixel == 8) {
+	}
+	
+	/******************************************************
+	 *
+	 * 8 bpp
+	 *
+	 */
+	
+	else if (_par->var.bits_per_pixel == 8) {
 		DPRINTK ("clgen: preparing for 8 bit deep display\n");
 		switch (fb_info->btype) {
 		case BT_SD64:
-			vga_wseq (fb_info->regs, CL_SEQR7, 0xf1);	/* Extended Sequencer Mode: 256c col. mode */
+		case BT_PICCOLO:
+		case BT_PICASSO:
+		case BT_SPECTRUM:
+		case BT_PICASSO4:
+		case BT_ALPINE:
+		case BT_GD5480:
+			DPRINTK (" (for GD54xx)\n");
+			vga_wseq (fb_info->regs, CL_SEQR7,
+				  _par->multiplexing ?
+				  	bi->sr07_8bpp_mux : bi->sr07_8bpp);
+			break;
+
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (fb_info->regs, CL_SEQR7,
+				vga_rseq (fb_info->regs, CL_SEQR7) | 0x01);
+			break;
+			
+		default:
+			printk (KERN_WARNING "clgen: unknown Board\n");
+			break;
+		}
+
+		switch (fb_info->btype) {
+		case BT_SD64:
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x1d);		/* MCLK select */
 			break;
 
 		case BT_PICCOLO:
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x81);
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
 			break;
 
 		case BT_PICASSO:
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x21);
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
 			break;
 
 		case BT_SPECTRUM:
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x81);
 			vga_wseq (fb_info->regs, CL_SEQR1F, 0x22);		/* ### vorher 1c MCLK select */
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);	/* Fast Page-Mode writes */
 			break;
 
 		case BT_PICASSO4:
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x21);
 			vga_wseq (fb_info->regs, CL_SEQRF, 0xb8);	/* ### INCOMPLETE!! */
 /*          vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
 			break;
 
 		case BT_ALPINE:
 			DPRINTK (" (for GD543x)\n");
-			if (_par->multiplexing)
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
-			else
-				vga_wseq (fb_info->regs, CL_SEQR7, 0xa1);
 			clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
 			/* We already set SRF and SR1F */
 			break;
 
 		case BT_GD5480:
-			DPRINTK (" (for GD5480)\n");
-			vga_wseq (fb_info->regs, CL_SEQR7, 0x11);
-			/* We already set SRF and SR1F */
+		case BT_LAGUNA:
+			DPRINTK (" (for GD54xx)\n");
+			/* do nothing */
 			break;
-
+			
 		default:
 			printk (KERN_WARNING "clgen: unknown Board\n");
 			break;
@@ -1348,7 +1482,15 @@
 		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
 		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
 		offset = _par->var.xres_virtual / 8;
-	} else if (_par->var.bits_per_pixel == 16) {
+	}
+	
+	/******************************************************
+	 *
+	 * 16 bpp
+	 *
+	 */
+	
+	else if (_par->var.bits_per_pixel == 16) {
 		DPRINTK ("clgen: preparing for 16 bit deep display\n");
 		switch (fb_info->btype) {
 		case BT_SD64:
@@ -1394,6 +1536,12 @@
 			/* We already set SRF and SR1F */
 			break;
 
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (fb_info->regs, CL_SEQR7,
+				vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
+			break;
+			
 		default:
 			printk (KERN_WARNING "CLGEN: unknown Board\n");
 			break;
@@ -1409,7 +1557,15 @@
 		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
 		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
 		offset = _par->var.xres_virtual / 4;
-	} else if (_par->var.bits_per_pixel == 32) {
+	}
+	
+	/******************************************************
+	 *
+	 * 32 bpp
+	 *
+	 */
+	
+	else if (_par->var.bits_per_pixel == 32) {
 		DPRINTK ("clgen: preparing for 24/32 bit deep display\n");
 		switch (fb_info->btype) {
 		case BT_SD64:
@@ -1452,6 +1608,12 @@
 			/* We already set SRF and SR1F */
 			break;
 
+		case BT_LAGUNA:
+			DPRINTK (" (for GD546x)\n");
+			vga_wseq (fb_info->regs, CL_SEQR7,
+				vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
+			break;
+			
 		default:
 			printk (KERN_WARNING "clgen: unknown Board\n");
 			break;
@@ -1463,10 +1625,19 @@
 		vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a);	/* memory mode: chain4, ext. memory */
 		vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff);	/* plane mask: enable writing to all 4 planes */
 		offset = _par->var.xres_virtual / 4;
-	} else
+	}
+	
+	/******************************************************
+	 *
+	 * unknown/unsupported bpp
+	 *
+	 */
+	
+	else {
 		printk (KERN_ERR "clgen: What's this?? requested color depth == %d.\n",
 			_par->var.bits_per_pixel);
-
+	}
+	
 	vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff);
 	tmp = 0x22;
 	if (offset & 0x100)
@@ -1531,26 +1702,23 @@
 	return;
 }
 
+
 static int clgen_getcolreg (unsigned regno, unsigned *red, unsigned *green,
 			    unsigned *blue, unsigned *transp,
 			    struct fb_info *info)
 {
-	unsigned char bred, bgreen, bblue;
-	struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
+    struct clgenfb_info *fb_info = (struct clgenfb_info *)info;
 
-	if (regno > 255)
-		return -EINVAL;
-
-	RClut (fb_info, regno, &bred, &bgreen, &bblue);
-
-	*red = (bred << 10) | (bred << 4) | (bred >> 2);
-	*green = (bgreen << 10) | (bgreen << 4) | (bgreen >> 2);
-	*blue = (bblue << 10) | (bblue << 4) | (bblue >> 2);
-	*transp = 0;
-
-	return 0;
+    if (regno > 255)
+	return 1;
+    *red = fb_info->palette[regno].red;
+    *green = fb_info->palette[regno].green;
+    *blue = fb_info->palette[regno].blue;
+    *transp = 0;
+    return 0;
 }
 
+
 static int clgen_setcolreg (unsigned regno, unsigned red, unsigned green,
 			    unsigned blue, unsigned transp,
 			    struct fb_info *info)
@@ -1560,13 +1728,27 @@
 	if (regno > 255)
 		return -EINVAL;
 
-	switch (fb_info->currentmode.var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
+	switch (fb_info->currentmode.var.bits_per_pixel) {
 	case 8:
 		/* "transparent" stuff is completely ignored. */
 		WClut (fb_info, regno, red >> 10, green >> 10, blue >> 10);
 		break;
-#endif
+	default:
+		/* do nothing */
+		break;
+	}
+#endif	/* FBCON_HAS_CFB8 */
+
+	fb_info->palette[regno].red = red;
+	fb_info->palette[regno].green = green;
+	fb_info->palette[regno].blue = blue;
+
+	if (regno >= 16)
+		return 0;
+		
+	switch (fb_info->currentmode.var.bits_per_pixel) {
+
 #ifdef FBCON_HAS_CFB16
 	case 16:
 		assert (regno < 16);
@@ -1582,7 +1764,18 @@
 		    ((green & 0xf800) >> 6) |
 		    ((blue & 0xf800) >> 11);
 #endif
-#endif
+#endif /* FBCON_HAS_CFB16 */
+
+#ifdef FBCON_HAS_CFB24
+	case 24:
+		assert (regno < 16);
+		fb_info->fbcon_cmap.cfb24[regno] =
+			(red   << fb_info->currentmode.var.red.offset)   |
+			(green << fb_info->currentmode.var.green.offset) |
+			(blue  << fb_info->currentmode.var.blue.offset);
+		break;
+#endif /* FBCON_HAS_CFB24 */
+
 #ifdef FBCON_HAS_CFB32
 	case 32:
 		assert (regno < 16);
@@ -1591,12 +1784,17 @@
 		    ((red & 0xff00)) |
 		    ((green & 0xff00) << 8) |
 		    ((blue & 0xff00) << 16);
-#endif
+#else
 		fb_info->fbcon_cmap.cfb32[regno] =
 		    ((red & 0xff00) << 8) |
 		    ((green & 0xff00)) |
 		    ((blue & 0xff00) >> 8);
 #endif
+		break;
+#endif /* FBCON_HAS_CFB32 */
+	default:
+		/* do nothing */
+		break;
 	}
 
 	return 0;
@@ -1848,7 +2046,8 @@
 	vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0e);	/* memory mode: chain-4, no odd/even, ext. memory */
 
 	/* controller-internal base address of video memory */
-	vga_wseq (fb_info->regs, CL_SEQR7, bi->sr07);
+	if (bi->init_sr07)
+		vga_wseq (fb_info->regs, CL_SEQR7, bi->sr07);
 
 	/*  vga_wseq (fb_info->regs, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
 
@@ -1864,7 +2063,7 @@
 	}
 
 	/* MCLK select etc. */
-	if (bi->write_sr1f)
+	if (bi->init_sr1f)
 		vga_wseq (fb_info->regs, CL_SEQR1F, bi->sr1f);
 
 	vga_wcrt (fb_info->regs, VGA_CRTC_PRESET_ROW, 0x00);	/* Screen A preset row scan: none */
@@ -2647,7 +2846,7 @@
 /********************************************************************/
 int __init clgenfb_init(void)
 {
-	int err;
+	int err, j, k;
 
 	clgen_board_t btype = BT_NONE;
 	struct clgenfb_info *fb_info = NULL;
@@ -2701,6 +2900,19 @@
 	fb_info->gen.info.blank = &fbgen_blank;
 	fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
 
+	for (j = 0; j < 256; j++) {
+		if (j < 16) {
+			k = color_table[j];
+			fb_info->palette[j].red = default_red[k];
+			fb_info->palette[j].green = default_grn[k];
+			fb_info->palette[j].blue = default_blu[k];
+		} else {
+			fb_info->palette[j].red =
+			fb_info->palette[j].green =
+			fb_info->palette[j].blue = j;
+		}
+	}
+
 	/* now that we know the board has been registered n' stuff, we */
 	/* can finally initialize it to a default mode */
 	clgenfb_default = clgenfb_predefined[clgen_def_mode].var;
@@ -2998,6 +3210,7 @@
 
 
 
+#if 0
 /*** RClut - read CLUT entry (range 0..63) ***/
 static void RClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char *red,
 	    unsigned char *green, unsigned char *blue)
@@ -3019,6 +3232,7 @@
 		*red = vga_r (fb_info->regs, data);
 	}
 }
+#endif
 
 
 /*******************************************************************
diff -u --recursive --new-file v2.3.17/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c
--- v2.3.17/linux/drivers/video/matroxfb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/matroxfb.c	Wed Sep  8 11:51:22 1999
@@ -111,9 +111,9 @@
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/pci.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
-#include <asm/spinlock.h>
 #include <asm/unaligned.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
diff -u --recursive --new-file v2.3.17/linux/drivers/video/p9100fb.c linux/drivers/video/p9100fb.c
--- v2.3.17/linux/drivers/video/p9100fb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/p9100fb.c	Wed Sep  8 11:14:32 1999
@@ -31,8 +31,9 @@
   { P9100_CTL_OFF, 0x38000000, 0x2000 },
   { P9100_CMD_OFF, 0x38002000, 0x2000 },
   { P9100_FB_OFF, 0x38800000, 0x200000 },
-#else
   { CG3_MMAP_OFFSET, 0x38800000, SBUS_MMAP_FBSIZE(1) },
+#else
+  { CG3_MMAP_OFFSET, 0x0, SBUS_MMAP_FBSIZE(1) },
 #endif
   { 0, 0, 0 }
 };
@@ -79,22 +80,6 @@
 		_READCTL(pwrup_cfg, tmp);
 		WRITECTL(ramdac_palette_data, (fb->color_map CM(i,2) << 16));
 	}
-#if 0
-	printk("updating %d colors starting at %d\n", count, index);
-
-	WRITECTL(ramdac_palette_rdaddr, index);
-	for (i = index; count--; i++){
-		_READCTL(pwrup_cfg, tmp);
-		READCTL(ramdac_palette_data, tmp);
-		printk("%d: red %x ", i, tmp);
-		_READCTL(pwrup_cfg, tmp);
-		READCTL(ramdac_palette_data, tmp);
-		printk("green %x ", tmp);
-		_READCTL(pwrup_cfg, tmp);
-		READCTL(ramdac_palette_data, tmp);
-		printk("blue %x\n", tmp);
-	}
-#endif
 }
 
 static void p9100_blank (struct fb_info_sbusfb *fb)
@@ -121,7 +106,7 @@
 
 static char idstring[60] __initdata = { 0 };
 
-char * __init p9100fb_init(struct fb_info_sbusfb *fb)
+__initfunc(char *p9100fb_init(struct fb_info_sbusfb *fb))
 {
 	struct fb_fix_screeninfo *fix = &fb->fix;
 	struct display *disp = &fb->disp;
@@ -140,7 +125,8 @@
 
 	if (!fb->s.p9100.ctrl) {
 	  fb->s.p9100.ctrl = (struct p9100_ctrl *)
-	    sparc_alloc_io(fb->sbdp->reg_addrs[0].phys_addr, 0, fb->sbdp->reg_addrs[1].reg_size, "p9100_ctrl", fb->iospace, 0);
+	    sparc_alloc_io(fb->sbdp->reg_addrs[0].phys_addr, 0, 
+			   fb->sbdp->reg_addrs[1].reg_size, "p9100_ctrl", fb->iospace, 0);
 	}
 
 	strcpy(fb->info.modename, "p9100");
diff -u --recursive --new-file v2.3.17/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.3.17/linux/drivers/video/sbusfb.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/video/sbusfb.c	Wed Sep  8 11:14:32 1999
@@ -1088,7 +1088,8 @@
 #endif
 #ifdef CONFIG_FB_P9100
 	case FBTYPE_P9100COLOR:
-		p = p9100fb_init(fb); break;
+		/* Temporary crock. For now we are a cg3 */
+		p = p9100fb_init(fb); type->fb_type = FBTYPE_SUN3COLOR; break;
 #endif
 	}
 	
diff -u --recursive --new-file v2.3.17/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.3.17/linux/fs/binfmt_misc.c	Tue Aug  3 10:18:39 1999
+++ linux/fs/binfmt_misc.c	Wed Sep  8 11:42:15 1999
@@ -27,8 +27,8 @@
 #include <linux/proc_fs.h>
 #include <linux/string.h>
 #include <linux/ctype.h>
+#include <linux/spinlock.h>
 #include <asm/uaccess.h>
-#include <asm/spinlock.h>
 
 /*
  * We should make this work with a "stub-only" /proc,
diff -u --recursive --new-file v2.3.17/linux/fs/pipe.c linux/fs/pipe.c
--- v2.3.17/linux/fs/pipe.c	Tue Sep  7 12:14:07 1999
+++ linux/fs/pipe.c	Wed Sep  8 11:20:20 1999
@@ -59,37 +59,32 @@
 	if (count == 0)
 		goto out_nolock;
 
-	/* Grab, or try to grab, the pipe's semaphore with data present.  */
-	if (filp->f_flags & O_NONBLOCK) {
+	/* Get the pipe semaphore */
+	ret = -ERESTARTSYS;
+	if (down_interruptible(PIPE_SEM(*inode)))
+		goto out_nolock;
+
+	if (PIPE_EMPTY(*inode)) {
+		ret = 0;
+		if (!PIPE_WRITERS(*inode))
+			goto out;
+
 		ret = -EAGAIN;
-		if (down_trylock(PIPE_SEM(*inode)))
-			goto out_nolock;
-		ret = PIPE_WRITERS(*inode) ? -EAGAIN : 0;
-		if (PIPE_EMPTY(*inode))
+		if (filp->f_flags & O_NONBLOCK)
 			goto out;
-	} else {
-		ret = -ERESTARTSYS;
-		if (down_interruptible(PIPE_SEM(*inode)))
-			goto out_nolock;
 
-		if (PIPE_EMPTY(*inode)) {
+		for (;;) {
+			pipe_wait(inode);
+			ret = -ERESTARTSYS;
+			if (signal_pending(current))
+				goto out_nolock;
+			if (down_interruptible(PIPE_SEM(*inode)))
+				goto out_nolock;
 			ret = 0;
+			if (!PIPE_EMPTY(*inode))
+				break;
 			if (!PIPE_WRITERS(*inode))
 				goto out;
-
-			for (;;) {
-				pipe_wait(inode);
-				ret = -ERESTARTSYS;
-				if (signal_pending(current))
-					goto out_nolock;
-				if (down_interruptible(PIPE_SEM(*inode)))
-					goto out_nolock;
-				ret = 0;
-				if (!PIPE_EMPTY(*inode))
-					break;
-				if (!PIPE_WRITERS(*inode))
-					goto out;
-			}
 		}
 	}
 
diff -u --recursive --new-file v2.3.17/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.17/linux/fs/proc/root.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/proc/root.c	Fri Sep 10 11:12:16 1999
@@ -641,6 +641,14 @@
 	NULL,
 	NULL, NULL
 };
+struct proc_dir_entry proc_root_driver = {
+        PROC_DRIVER, 6, "driver",
+        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+        0, &proc_dir_inode_operations,
+	NULL, NULL,
+	NULL,
+	NULL, NULL
+};
 static struct proc_dir_entry proc_root_dma = {
 	PROC_DMA, 3, "dma",
 	S_IFREG | S_IRUGO, 1, 0, 0,
@@ -738,6 +746,7 @@
 #endif
 	proc_register(&proc_root, &proc_root_stat);
 	proc_register(&proc_root, &proc_root_devices);
+	proc_register(&proc_root, &proc_root_driver);
 	proc_register(&proc_root, &proc_root_partitions);
 	proc_register(&proc_root, &proc_root_interrupts);
 	proc_register(&proc_root, &proc_root_filesystems);
diff -u --recursive --new-file v2.3.17/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.3.17/linux/fs/udf/file.c	Tue Sep  7 12:14:07 1999
+++ linux/fs/udf/file.c	Wed Sep  8 11:14:32 1999
@@ -168,15 +168,12 @@
 			break;
 		}
 	}
+#if BITS_PER_LONG < 64
 	if (((unsigned long long) offset >> 32) != 0)
 	{
-#if BITS_PER_LONG < 64
 		return -EINVAL;
-#else
-		if (offset > ???)
-			return -EINVAL;
-#endif
 	}
+#endif
 	if (offset != file->f_pos)
 	{
 		file->f_pos = offset;
diff -u --recursive --new-file v2.3.17/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.3.17/linux/fs/udf/super.c	Tue Sep  7 12:14:07 1999
+++ linux/fs/udf/super.c	Wed Sep  8 11:14:32 1999
@@ -183,7 +183,7 @@
 		int size;
 
 		size = sizeof(struct super_block) +
-			(int)&sb.u - (int)&sb;
+			(long)&sb.u - (long)&sb;
 		if ( size < sizeof(struct udf_sb_info) )
 		{
 			printk(KERN_ERR "udf: Danger! Kernel was compiled without enough room for udf_sb_info\n");
diff -u --recursive --new-file v2.3.17/linux/fs/udf/udfend.h linux/fs/udf/udfend.h
--- v2.3.17/linux/fs/udf/udfend.h	Tue Sep  7 12:14:07 1999
+++ linux/fs/udf/udfend.h	Wed Sep  8 11:14:32 1999
@@ -46,6 +46,10 @@
 
 #endif
 
+#ifdef __KERNEL__
+#include <linux/string.h>
+#endif
+
 static inline lb_addr lelb_to_cpu(lb_addr in)
 {
 	lb_addr out;
diff -u --recursive --new-file v2.3.17/linux/include/asm-alpha/dma.h linux/include/asm-alpha/dma.h
--- v2.3.17/linux/include/asm-alpha/dma.h	Thu Aug 26 13:05:40 1999
+++ linux/include/asm-alpha/dma.h	Wed Sep  8 11:55:45 1999
@@ -19,8 +19,8 @@
 #define _ASM_DMA_H
 
 #include <linux/config.h>
+#include <linux/spinlock.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
 
 #define dma_outb	outb
 #define dma_inb		inb
diff -u --recursive --new-file v2.3.17/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.3.17/linux/include/asm-alpha/hardirq.h	Wed Aug  4 15:42:06 1999
+++ linux/include/asm-alpha/hardirq.h	Wed Sep  8 11:55:45 1999
@@ -36,7 +36,7 @@
 #else
 
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/smp.h>
 
 extern int global_irq_holder;
diff -u --recursive --new-file v2.3.17/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.3.17/linux/include/asm-alpha/pgtable.h	Thu Aug 26 13:05:40 1999
+++ linux/include/asm-alpha/pgtable.h	Wed Sep  8 11:54:14 1999
@@ -9,12 +9,12 @@
  * in <asm/page.h> (currently 8192).
  */
 #include <linux/config.h>
+#include <linux/spinlock.h>	/* For the task lock */
 
 #include <asm/system.h>
 #include <asm/processor.h>	/* For TASK_SIZE */
 #include <asm/mmu_context.h>
 #include <asm/machvec.h>
-#include <asm/spinlock.h>	/* For the task lock */
 
 
 /* Caches aren't brain-dead on the Alpha. */
diff -u --recursive --new-file v2.3.17/linux/include/asm-alpha/smplock.h linux/include/asm-alpha/smplock.h
--- v2.3.17/linux/include/asm-alpha/smplock.h	Sun Sep  6 10:34:33 1998
+++ linux/include/asm-alpha/smplock.h	Wed Sep  8 11:54:14 1999
@@ -6,7 +6,7 @@
 
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h
--- v2.3.17/linux/include/asm-alpha/spinlock.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-alpha/spinlock.h	Wed Sep  8 12:02:38 1999
@@ -2,103 +2,6 @@
 #define _ALPHA_SPINLOCK_H
 
 #include <asm/system.h>
-
-/*
- * These are the generic versions of the spinlocks
- * and read-write locks.. We should actually do a
- * <linux/spinlock.h> with all of this. Oh, well.
- */
-#define spin_lock_irqsave(lock, flags) \
-  do { local_irq_save(flags); spin_lock(lock); } while (0)
-#define spin_lock_irq(lock) \
-  do { local_irq_disable(); spin_lock(lock); } while (0)
-#define spin_lock_bh(lock) \
-  do { local_bh_disable(); spin_lock(lock); } while (0)
-
-#define read_lock_irqsave(lock, flags) \
-  do { local_irq_save(flags); read_lock(lock); } while (0)
-#define read_lock_irq(lock) \
-  do { local_irq_disable(); read_lock(lock); } while (0)
-#define read_lock_bh(lock) \
-  do { local_bh_disable(); read_lock(lock); } while (0)
-
-#define write_lock_irqsave(lock, flags) \
-  do { local_irq_save(flags); write_lock(lock); } while (0)
-#define write_lock_irq(lock) \
-  do { local_irq_disable(); write_lock(lock); } while (0)
-#define write_lock_bh(lock) \
-  do { local_bh_disable(); write_lock(lock); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags) \
-  do { spin_unlock(lock); local_irq_restore(flags); } while (0)
-#define spin_unlock_irq(lock) \
-  do { spin_unlock(lock); local_irq_enable(); } while (0)
-#define spin_unlock_bh(lock) \
-  do { spin_unlock(lock); local_bh_enable(); } while (0)
-
-#define read_unlock_irqrestore(lock, flags) \
-  do { read_unlock(lock); local_irq_restore(flags); } while (0)
-#define read_unlock_irq(lock) \
-  do { read_unlock(lock); local_irq_enable(); } while (0)
-#define read_unlock_bh(lock) \
-  do { read_unlock(lock); local_bh_enable(); } while (0)
-
-#define write_unlock_irqrestore(lock, flags) \
-  do { write_unlock(lock); local_irq_restore(flags); } while (0)
-#define write_unlock_irq(lock) \
-  do { write_unlock(lock); local_irq_enable(); } while (0)
-#define write_unlock_bh(lock) \
-  do { write_unlock(lock); local_bh_enable(); } while (0)
-
-#ifndef __SMP__
-
-/*
- * Your basic spinlocks, allowing only a single CPU anywhere
- *
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#endif
-
-#define spin_lock_init(lock)			((void)(lock))
-#define spin_lock(lock)				((void)(lock))
-#define spin_trylock(lock)			((void)(lock), 1)
-#define spin_unlock_wait(lock)			((void)(lock))
-#define spin_unlock(lock)			((void)(lock))
-#define spin_is_locked(lock)			((void)(lock), 0)
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- *
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
-#endif
-
-#define read_lock(lock)				((void)(lock))
-#define read_unlock(lock)			((void)(lock))
-#define write_lock(lock)			((void)(lock))
-#define write_unlock(lock)			((void)(lock))
-
-#else /* __SMP__ */
-
 #include <linux/kernel.h>
 #include <asm/current.h>
 
@@ -264,5 +167,4 @@
 	: "m" (__dummy_lock(lock)));
 }
 
-#endif /* SMP */
 #endif /* _ALPHA_SPINLOCK_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h
--- v2.3.17/linux/include/asm-arm/dma.h	Thu Aug 26 13:05:40 1999
+++ linux/include/asm-arm/dma.h	Wed Sep  8 11:55:45 1999
@@ -5,8 +5,8 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/spinlock.h>
 #include <asm/irq.h>
-#include <asm/spinlock.h>
 #include <asm/arch/dma.h>
 
 /*
diff -u --recursive --new-file v2.3.17/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.3.17/linux/include/asm-arm/semaphore.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/semaphore.h	Wed Sep  8 11:54:14 1999
@@ -6,7 +6,7 @@
 
 #include <linux/linkage.h>
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/wait.h>
 
 struct semaphore {
diff -u --recursive --new-file v2.3.17/linux/include/asm-arm/smplock.h linux/include/asm-arm/smplock.h
--- v2.3.17/linux/include/asm-arm/smplock.h	Mon Aug  3 12:28:20 1998
+++ linux/include/asm-arm/smplock.h	Wed Sep  8 11:54:14 1999
@@ -4,7 +4,7 @@
  * Default SMP lock implementation
  */
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-arm/spinlock.h linux/include/asm-arm/spinlock.h
--- v2.3.17/linux/include/asm-arm/spinlock.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-arm/spinlock.h	Wed Sep  8 12:01:38 1999
@@ -1,116 +1,6 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-/*
- * To be safe, we assume the only compiler that can cope with
- * empty initialisers is EGCS.
- */
-#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 90))
-#define EMPTY_STRUCT		struct { }
-#define EMPTY_STRUCT_INIT(t)	(t) { }
-#else
-#define EMPTY_STRUCT		unsigned char
-#define EMPTY_STRUCT_INIT(t)	(t) 0
-#endif
+#error ARM architecture does not support SMP spin locks
 
-/*
- * These are the generic versions of the spinlocks
- * and read-write locks.. We should actually do a
- * <linux/spinlock.h> with all of this. Oh, well.
- */
-#define spin_lock_irqsave(lock, flags)		do { local_irq_save(flags);       spin_lock(lock); } while (0)
-#define spin_lock_irq(lock)			do { local_irq_disable();         spin_lock(lock); } while (0)
-#define spin_lock_bh(lock)			do { local_bh_disable();          spin_lock(lock); } while (0)
-
-#define read_lock_irqsave(lock, flags)		do { local_irq_save(flags);       read_lock(lock); } while (0)
-#define read_lock_irq(lock)			do { local_irq_disable();         read_lock(lock); } while (0)
-#define read_lock_bh(lock)			do { local_bh_disable();          read_lock(lock); } while (0)
-
-#define write_lock_irqsave(lock, flags)		do { local_irq_save(flags);      write_lock(lock); } while (0)
-#define write_lock_irq(lock)			do { local_irq_disable();        write_lock(lock); } while (0)
-#define write_lock_bh(lock)			do { local_bh_disable();         write_lock(lock); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags)	do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
-#define spin_unlock_irq(lock)			do { spin_unlock(lock);  local_irq_enable();       } while (0)
-#define spin_unlock_bh(lock)			do { spin_unlock(lock);  local_bh_enable();        } while (0)
-
-#define read_unlock_irqrestore(lock, flags)	do { read_unlock(lock);  local_irq_restore(flags); } while (0)
-#define read_unlock_irq(lock)			do { read_unlock(lock);  local_irq_enable();       } while (0)
-#define read_unlock_bh(lock)			do { read_unlock(lock);  local_bh_enable();        } while (0)
-
-#define write_unlock_irqrestore(lock, flags)	do { write_unlock(lock); local_irq_restore(flags); } while (0)
-#define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
-#define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
-
-#ifndef __SMP__
-
-#define DEBUG_SPINLOCKS 0	/* 0 == no debugging, 1 == maintain lock state, 2 == full debugging */
-
-#if (DEBUG_SPINLOCKS < 1)
-/*
- * Your basic spinlocks, allowing only a single CPU anywhere
- */
-typedef EMPTY_STRUCT spinlock_t;
-#define SPIN_LOCK_UNLOCKED EMPTY_STRUCT_INIT(spinlock_t)
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-
-#elif (DEBUG_SPINLOCKS < 2)
-
-typedef struct {
-	volatile unsigned int lock;
-} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (pinlock_t) { 0 }
-
-#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
-#define spin_lock(x)		do { (x)->lock = 1; } while (0)
-#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
-#define spin_unlock_wait(x)	do { } while (0)
-#define spin_unlock(x)		do { (x)->lock = 0; } while (0)
-
-#else /* (DEBUG_SPINLOCKS >= 2) */
-
-typedef struct {
-	volatule unsigned int lock;
-	volatile unsigned int babble;
-	const char *module;
-} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
-
-#include <linux/kernel.h>
-
-#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
-#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
-
-#define spin_lock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
-#define spin_unlock_wait(x)	do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
-#define spin_unlock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
-
-#endif
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-typedef EMPTY_STRUCT rwlock_t;
-#define RW_LOCK_UNLOCKED EMPTY_STRUCT_INIT(rwlock_t)
-
-#define read_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	(void)(lock) /* Not "unused variable". */
-#define write_unlock(lock)	do { } while(0)
-
-#else
-#error ARM architecture does not support spin locks
-#endif /* SMP */
 #endif /* __ASM_SPINLOCK_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-generic/smplock.h linux/include/asm-generic/smplock.h
--- v2.3.17/linux/include/asm-generic/smplock.h	Mon Aug  3 12:28:20 1998
+++ linux/include/asm-generic/smplock.h	Wed Sep  8 11:54:14 1999
@@ -4,7 +4,7 @@
  * Default SMP lock implementation
  */
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-i386/dma.h linux/include/asm-i386/dma.h
--- v2.3.17/linux/include/asm-i386/dma.h	Thu Aug 26 13:05:40 1999
+++ linux/include/asm-i386/dma.h	Thu Sep  9 22:17:36 1999
@@ -9,8 +9,8 @@
 #define _ASM_DMA_H
 
 #include <linux/config.h>
+#include <linux/spinlock.h>	/* And spinlocks */
 #include <asm/io.h>		/* need byte IO */
-#include <asm/spinlock.h>	/* And spinlocks */
 #include <linux/delay.h>
 
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- v2.3.17/linux/include/asm-i386/semaphore.h	Thu Aug 26 13:05:41 1999
+++ linux/include/asm-i386/semaphore.h	Thu Sep  9 22:17:31 1999
@@ -30,7 +30,7 @@
 
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/wait.h>
 
 struct semaphore {
diff -u --recursive --new-file v2.3.17/linux/include/asm-i386/smplock.h linux/include/asm-i386/smplock.h
--- v2.3.17/linux/include/asm-i386/smplock.h	Wed Aug 18 16:43:33 1999
+++ linux/include/asm-i386/smplock.h	Thu Sep  9 22:17:31 1999
@@ -4,7 +4,7 @@
  * i386 SMP lock implementation
  */
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-i386/spinlock.h linux/include/asm-i386/spinlock.h
--- v2.3.17/linux/include/asm-i386/spinlock.h	Wed Aug 18 16:43:28 1999
+++ linux/include/asm-i386/spinlock.h	Wed Sep  8 12:01:38 1999
@@ -2,122 +2,7 @@
 #define __ASM_SPINLOCK_H
 
 /*
- * These are the generic versions of the spinlocks
- * and read-write locks.. We should actually do a
- * <linux/spinlock.h> with all of this. Oh, well.
- */
-#define spin_lock_irqsave(lock, flags)		do { local_irq_save(flags);       spin_lock(lock); } while (0)
-#define spin_lock_irq(lock)			do { local_irq_disable();         spin_lock(lock); } while (0)
-#define spin_lock_bh(lock)			do { local_bh_disable();          spin_lock(lock); } while (0)
-
-#define read_lock_irqsave(lock, flags)		do { local_irq_save(flags);       read_lock(lock); } while (0)
-#define read_lock_irq(lock)			do { local_irq_disable();         read_lock(lock); } while (0)
-#define read_lock_bh(lock)			do { local_bh_disable();          read_lock(lock); } while (0)
-
-#define write_lock_irqsave(lock, flags)		do { local_irq_save(flags);      write_lock(lock); } while (0)
-#define write_lock_irq(lock)			do { local_irq_disable();        write_lock(lock); } while (0)
-#define write_lock_bh(lock)			do { local_bh_disable();         write_lock(lock); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags)	do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
-#define spin_unlock_irq(lock)			do { spin_unlock(lock);  local_irq_enable();       } while (0)
-#define spin_unlock_bh(lock)			do { spin_unlock(lock);  local_bh_enable();        } while (0)
-
-#define read_unlock_irqrestore(lock, flags)	do { read_unlock(lock);  local_irq_restore(flags); } while (0)
-#define read_unlock_irq(lock)			do { read_unlock(lock);  local_irq_enable();       } while (0)
-#define read_unlock_bh(lock)			do { read_unlock(lock);  local_bh_enable();        } while (0)
-
-#define write_unlock_irqrestore(lock, flags)	do { write_unlock(lock); local_irq_restore(flags); } while (0)
-#define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
-#define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
-
-#ifndef __SMP__
-
-#define DEBUG_SPINLOCKS	0	/* 0 == no debugging, 1 == maintain lock state, 2 == full debug */
-
-#if (DEBUG_SPINLOCKS < 1)
-
-/*
- * Your basic spinlocks, allowing only a single CPU anywhere
- *
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#endif
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-
-#elif (DEBUG_SPINLOCKS < 2)
-
-typedef struct {
-	volatile unsigned int lock;
-} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-
-#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
-#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
-
-#define spin_lock(x)		do { (x)->lock = 1; } while (0)
-#define spin_unlock_wait(x)	do { } while (0)
-#define spin_unlock(x)		do { (x)->lock = 0; } while (0)
-
-#else /* (DEBUG_SPINLOCKS >= 2) */
-
-typedef struct {
-	volatile unsigned int lock;
-	volatile unsigned int babble;
-	const char *module;
-} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
-
-#include <linux/kernel.h>
-
-#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
-#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
-
-#define spin_lock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
-#define spin_unlock_wait(x)	do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
-#define spin_unlock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
-
-#endif	/* DEBUG_SPINLOCKS */
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- *
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
-#endif
-
-#define read_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	(void)(lock) /* Not "unused variable". */
-#define write_unlock(lock)	do { } while(0)
-
-#else	/* __SMP__ */
-
-/*
- * Your basic spinlocks, allowing only a single CPU anywhere
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
  */
 
 typedef struct {
@@ -221,5 +106,4 @@
 #define write_unlock(rw) \
 	asm volatile("lock ; btrl $31,%0":"=m" (__dummy_lock(&(rw)->lock)))
 
-#endif /* __SMP__ */
 #endif /* __ASM_SPINLOCK_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.3.17/linux/include/asm-m68k/semaphore.h	Mon Aug  9 12:27:31 1999
+++ linux/include/asm-m68k/semaphore.h	Wed Sep  8 11:54:14 1999
@@ -3,10 +3,10 @@
 
 #include <linux/linkage.h>
 #include <linux/wait.h>
+#include <linux/spinlock.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
 
 /*
  * SMP- and interrupt-safe semaphores..
diff -u --recursive --new-file v2.3.17/linux/include/asm-m68k/smplock.h linux/include/asm-m68k/smplock.h
--- v2.3.17/linux/include/asm-m68k/smplock.h	Mon Aug  3 12:28:20 1998
+++ linux/include/asm-m68k/smplock.h	Wed Sep  8 11:54:14 1999
@@ -4,7 +4,7 @@
  * Default SMP lock implementation
  */
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-m68k/spinlock.h linux/include/asm-m68k/spinlock.h
--- v2.3.17/linux/include/asm-m68k/spinlock.h	Mon Aug  9 12:27:31 1999
+++ linux/include/asm-m68k/spinlock.h	Wed Sep  8 12:01:38 1999
@@ -1,72 +1,6 @@
 #ifndef __M68K_SPINLOCK_H
 #define __M68K_SPINLOCK_H
 
-/*
- * We don't do SMP on the m68k .... at least not yet.
- */
-
-/*
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-#else
-typedef struct { int gcc_is_buggy; } spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#endif
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-#define spin_lock_irq(lock)	cli()
-#define spin_unlock_irq(lock)	sti()
-#define spin_lock_bh(lock)	local_bh_disable()
-#define spin_unlock_bh(lock)	local_bh_enable()
-
-#define spin_lock_irqsave(lock, flags) \
-	do { save_flags(flags); cli(); } while (0)
-#define spin_unlock_irqrestore(lock, flags) \
-	restore_flags(flags)
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- *
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { }
-#else
-typedef struct { int gcc_is_buggy; } rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
-#endif
-
-#define read_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	(void)(lock) /* Not "unused variable". */
-#define write_unlock(lock)	do { } while(0)
-#define read_lock_irq(lock)	cli()
-#define read_unlock_irq(lock)	sti()
-#define write_lock_irq(lock)	cli()
-#define write_unlock_irq(lock)	sti()
-#define read_lock_bh(lock)	local_bh_disable()
-#define read_unlock_bh(lock)	local_bh_enable()
-#define write_lock_bh(lock)	local_bh_disable()
-#define write_unlock_bh(lock)	local_bh_enable()
-
-#define read_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define read_unlock_irqrestore(lock, flags)	restore_flags(flags)
-#define write_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define write_unlock_irqrestore(lock, flags)	restore_flags(flags)
+#error "m68k doesn't do SMP"
 
 #endif
diff -u --recursive --new-file v2.3.17/linux/include/asm-mips/dma.h linux/include/asm-mips/dma.h
--- v2.3.17/linux/include/asm-mips/dma.h	Fri Jun 25 17:37:53 1999
+++ linux/include/asm-mips/dma.h	Wed Sep  8 11:55:45 1999
@@ -14,7 +14,7 @@
 
 #include <linux/config.h>
 #include <asm/io.h>			/* need byte IO */
-#include <asm/spinlock.h>		/* And spinlocks */
+#include <linux/spinlock.h>		/* And spinlocks */
 #include <linux/delay.h>
 #include <asm/system.h>
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-mips/semaphore.h linux/include/asm-mips/semaphore.h
--- v2.3.17/linux/include/asm-mips/semaphore.h	Fri Jun 25 17:37:53 1999
+++ linux/include/asm-mips/semaphore.h	Wed Sep  8 11:54:14 1999
@@ -14,7 +14,7 @@
 
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <linux/wait.h>
 
 struct semaphore {
diff -u --recursive --new-file v2.3.17/linux/include/asm-mips/smplock.h linux/include/asm-mips/smplock.h
--- v2.3.17/linux/include/asm-mips/smplock.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/smplock.h	Wed Sep  8 11:54:14 1999
@@ -7,7 +7,7 @@
  * Default SMP lock implementation
  */
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-mips/spinlock.h linux/include/asm-mips/spinlock.h
--- v2.3.17/linux/include/asm-mips/spinlock.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-mips/spinlock.h	Wed Sep  8 12:01:38 1999
@@ -3,75 +3,6 @@
 #ifndef __ASM_MIPS_SPINLOCK_H
 #define __ASM_MIPS_SPINLOCK_H
 
-/*
- * These are the generic versions of the spinlocks
- * and read-write locks.. We should actually do a
- * <linux/spinlock.h> with all of this. Oh, well.
- */
-#define spin_lock_irqsave(lock, flags)		do { local_irq_save(flags);       spin_lock(lock); } while (0)
-#define spin_lock_irq(lock)			do { local_irq_disable();         spin_lock(lock); } while (0)
-#define spin_lock_bh(lock)			do { local_bh_disable();          spin_lock(lock); } while (0)
-
-#define read_lock_irqsave(lock, flags)		do { local_irq_save(flags);       read_lock(lock); } while (0)
-#define read_lock_irq(lock)			do { local_irq_disable();         read_lock(lock); } while (0)
-#define read_lock_bh(lock)			do { local_bh_disable();          read_lock(lock); } while (0)
-
-#define write_lock_irqsave(lock, flags)		do { local_irq_save(flags);      write_lock(lock); } while (0)
-#define write_lock_irq(lock)			do { local_irq_disable();        write_lock(lock); } while (0)
-#define write_lock_bh(lock)			do { local_bh_disable();         write_lock(lock); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags)	do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
-#define spin_unlock_irq(lock)			do { spin_unlock(lock);  local_irq_enable();       } while (0)
-#define spin_unlock_bh(lock)			do { spin_unlock(lock);  local_bh_enable();        } while (0)
-
-#define read_unlock_irqrestore(lock, flags)	do { read_unlock(lock);  local_irq_restore(flags); } while (0)
-#define read_unlock_irq(lock)			do { read_unlock(lock);  local_irq_enable();       } while (0)
-#define read_unlock_bh(lock)			do { read_unlock(lock);  local_bh_enable();        } while (0)
-
-#define write_unlock_irqrestore(lock, flags)	do { write_unlock(lock); local_irq_restore(flags); } while (0)
-#define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
-#define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
-
-#ifndef __SMP__
-
-/*
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#endif
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		do { } while(0)
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { }
-
-#define read_lock(lock)		do { } while(0)
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	do { } while(0)
-#define write_unlock(lock)	do { } while(0)
-
-#else
-
 #error "Nix SMP on MIPS"
 
-#endif /* SMP */
 #endif /* __ASM_MIPS_SPINLOCK_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.3.17/linux/include/asm-ppc/dma.h	Thu Aug 26 13:05:41 1999
+++ linux/include/asm-ppc/dma.h	Wed Sep  8 11:55:45 1999
@@ -8,7 +8,7 @@
 
 #include <linux/config.h>
 #include <asm/io.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 
 /*
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/gemini.h linux/include/asm-ppc/gemini.h
--- v2.3.17/linux/include/asm-ppc/gemini.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/gemini.h	Wed Sep  8 10:59:07 1999
@@ -160,6 +160,7 @@
 
 
 extern void _gemini_reboot(void);
+extern void gemini_prom_init(void);
 extern void gemini_init_l2(void);
 #endif /* __ASSEMBLY__ */
 #endif
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/gemini_serial.h linux/include/asm-ppc/gemini_serial.h
--- v2.3.17/linux/include/asm-ppc/gemini_serial.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-ppc/gemini_serial.h	Wed Sep  8 10:59:07 1999
@@ -4,14 +4,20 @@
 #include <linux/config.h>
 #include <asm/gemini.h>
 
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  4
+#endif
+
 /* Rate for the 24.576 Mhz clock for the onboard serial chip */
 #define BASE_BAUD  (24576000 / 16)
 
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (/*ASYNC_BOOT_AUTOCONF|*/ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
 #define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM_FLAGS (/*ASYNC_BOOT_AUTOCONF|*/ASYNC_SKIP_TEST)
 #define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF)
 #endif
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/init.h linux/include/asm-ppc/init.h
--- v2.3.17/linux/include/asm-ppc/init.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/init.h	Wed Sep  8 10:59:07 1999
@@ -3,7 +3,8 @@
 
 #include <linux/init.h>
 
-#if 0/*__GNUC__ > 2 || __GNUC_MINOR__ >= 90*/ /* egcs */
+#if __GNUC__ > 2 || __GNUC_MINOR__ >= 90 /* egcs */
+#define __pmac __attribute__ ((__section__ (".text.pmac")))
 #define __pmacdata __attribute__ ((__section__ (".data.pmac")))
 #define __pmacfunc(__argpmac) \
 	__argpmac __pmac; \
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.3.17/linux/include/asm-ppc/keyboard.h	Mon Jun 28 13:40:39 1999
+++ linux/include/asm-ppc/keyboard.h	Wed Sep  8 10:59:07 1999
@@ -28,33 +28,47 @@
 
 static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	return ppc_md.kbd_setkeycode(scancode, keycode);
+	if ( ppc_md.kbd_setkeycode )
+		return ppc_md.kbd_setkeycode(scancode, keycode);
+	else
+		return 0;
 }
   
 static inline int kbd_getkeycode(unsigned int scancode)
 {
-	return ppc_md.kbd_getkeycode(scancode);
+	if ( ppc_md.kbd_getkeycode )
+		return ppc_md.kbd_getkeycode(scancode);
+	else
+		return 0;
 }
   
 static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
 				char raw_mode)
 {
-	return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
+	if ( ppc_md.kbd_translate )
+		return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
+	else
+		return 0;
 }
   
 static inline int kbd_unexpected_up(unsigned char keycode)
 {
-	return ppc_md.kbd_unexpected_up(keycode);
+	if ( ppc_md.kbd_unexpected_up )
+		return ppc_md.kbd_unexpected_up(keycode);
+	else
+		return 0;
 }
   
 static inline void kbd_leds(unsigned char leds)
 {
-	ppc_md.kbd_leds(leds);
+	if ( ppc_md.kbd_leds )
+		ppc_md.kbd_leds(leds);
 }
   
 static inline void kbd_init_hw(void)
 {
-	ppc_md.kbd_init_hw();
+	if ( ppc_md.kbd_init_hw )
+		ppc_md.kbd_init_hw();
 }
 
 #define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.3.17/linux/include/asm-ppc/machdep.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/machdep.h	Wed Sep  8 10:59:07 1999
@@ -72,6 +72,8 @@
 	int (*pcibios_write_config_dword)(unsigned char bus,
 		unsigned char dev_fn, unsigned char offset, unsigned int val);
 	void (*pcibios_fixup)(void);
+struct pci_bus;	
+	void (*pcibios_fixup_bus)(struct pci_bus *);
 };
 
 extern struct machdep_calls ppc_md;
@@ -90,7 +92,8 @@
 	int _machine;
 	unsigned long initrd_start, initrd_size;
 	unsigned long systemmap_start, systemmap_size;
-	char reserved[3684];	/* pad to 1 page */
+	unsigned long prom_entry;
+	char reserved[3680];	/* pad to 1 page */
 	unsigned long magic_end;
 };
 struct boot_info *binfo;
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h
--- v2.3.17/linux/include/asm-ppc/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/pci.h	Wed Sep  8 10:59:07 1999
@@ -0,0 +1,10 @@
+#ifndef __PPC_PCI_H
+#define __PPC_PCI_H
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+ * already-configured bus numbers - to be used for buggy BIOSes
+ * or architectures with incomplete PCI setup by the loader.
+ */
+#define pcibios_assign_all_busses()	0
+
+#endif /* __PPC_PCI_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.3.17/linux/include/asm-ppc/semaphore.h	Sat May 22 13:03:00 1999
+++ linux/include/asm-ppc/semaphore.h	Wed Sep  8 10:59:07 1999
@@ -1,5 +1,5 @@
-#ifndef _SPARC_SEMAPHORE_H
-#define _SPARC_SEMAPHORE_H
+#ifndef _PPC_SEMAPHORE_H
+#define _PPC_SEMAPHORE_H
 
 /*
  * Swiped from asm-sparc/semaphore.h and modified
@@ -104,4 +104,4 @@
 
 #endif /* __KERNEL__ */
 
-#endif /* !(_SPARC_SEMAPHORE_H) */
+#endif /* !(_PPC_SEMAPHORE_H) */
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/serial.h linux/include/asm-ppc/serial.h
--- v2.3.17/linux/include/asm-ppc/serial.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/serial.h	Wed Sep  8 10:59:07 1999
@@ -7,9 +7,23 @@
 #ifdef CONFIG_APUS
 #include <asm-m68k/serial.h>
 #else
+#ifdef CONFIG_GEMINI
+#include <asm/gemini_serial.h>
+#else
 
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+ * It'd be nice if someone built a serial card with a 24.576 MHz
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
 #define BASE_BAUD ( 1843200 / 16 )
-  
+
+#ifdef CONFIG_PMAC
+/*
+ * Auto-probing will cause machine checks on powermacs.
+ */
 #define SERIAL_PORT_DFNS
   
 #ifdef CONFIG_SERIAL_MANY_PORTS
@@ -17,5 +31,116 @@
 #else
 #define RS_TABLE_SIZE  4
 #endif
-  
+
+#else
+#define SERIAL_PORT_DFNS
+/*
+ * PReP, CHRP, etc.
+ */
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
+#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
+#else
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+#endif
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define FOURPORT_FLAGS ASYNC_FOURPORT
+#define ACCENT_FLAGS 0
+#define BOCA_FLAGS 0
+#define HUB6_FLAGS 0
+#endif
+	
+/*
+ * The following define the access methods for the HUB6 card. All
+ * access is through two ports for all 24 possible chips. The card is
+ * selected through the high 2 bits, the port on that card with the
+ * "middle" 3 bits, and the register on that port with the bottom
+ * 3 bits.
+ *
+ * While the access port and interrupt is configurable, the default
+ * port locations are 0x302 for the port control register, and 0x303
+ * for the data read/write register. Normally, the interrupt is at irq3
+ * but can be anything from 3 to 7 inclusive. Note that using 3 will
+ * require disabling com2.
+ */
+
+#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
+
+#define STD_SERIAL_PORT_DEFNS			\
+	/* UART CLK   PORT IRQ     FLAGS        */			\
+	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
+	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
+	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
+
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define EXTRA_SERIAL_PORT_DEFNS			\
+	{ 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, 	/* ttyS4 */	\
+	{ 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS },	/* ttyS5 */	\
+	{ 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS },	/* ttyS6 */	\
+	{ 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS },	/* ttyS7 */	\
+	{ 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS },	/* ttyS8 */	\
+	{ 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS },	/* ttyS9 */	\
+	{ 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS },	/* ttyS10 */	\
+	{ 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS },	/* ttyS11 */	\
+	{ 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS },	/* ttyS12 */	\
+	{ 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS },	/* ttyS13 */	\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS14 (spare) */		\
+	{ 0, BASE_BAUD, 0x000, 0, 0 },	/* ttyS15 (spare) */		\
+	{ 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS },	/* ttyS16 */	\
+	{ 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS },	/* ttyS17 */	\
+	{ 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS },	/* ttyS18 */	\
+	{ 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS },	/* ttyS19 */	\
+	{ 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS },	/* ttyS20 */	\
+	{ 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS },	/* ttyS21 */	\
+	{ 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS },	/* ttyS22 */	\
+	{ 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS },	/* ttyS23 */	\
+	{ 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS },	/* ttyS24 */	\
+	{ 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS },	/* ttyS25 */	\
+	{ 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS },	/* ttyS26 */	\
+	{ 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS },	/* ttyS27 */	\
+	{ 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS },	/* ttyS28 */	\
+	{ 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS },	/* ttyS29 */	\
+	{ 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS },	/* ttyS30 */	\
+	{ 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS },	/* ttyS31 */
+#else
+#define EXTRA_SERIAL_PORT_DEFNS
+#endif
+
+/* You can have up to four HUB6's in the system, but I've only
+ * included two cards here for a total of twelve ports.
+ */
+#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
+#define HUB6_SERIAL_PORT_DFNS		\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) },  /* ttyS32 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) },  /* ttyS33 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) },  /* ttyS34 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) },  /* ttyS35 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) },  /* ttyS36 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) },  /* ttyS37 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) },  /* ttyS38 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) },  /* ttyS39 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) },  /* ttyS40 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) },  /* ttyS41 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) },  /* ttyS42 */	\
+	{ 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) },  /* ttyS43 */
+#else
+#define HUB6_SERIAL_PORT_DFNS
+#endif
+
+#define MCA_SERIAL_PORT_DFNS
+
+#define SERIAL_PORT_DFNS		\
+	STD_SERIAL_PORT_DEFNS		\
+	EXTRA_SERIAL_PORT_DEFNS		\
+	HUB6_SERIAL_PORT_DFNS		\
+	MCA_SERIAL_PORT_DFNS
+
+#endif /* CONFIG_PMAC */
+#endif /* CONFIG_GEMINI */
 #endif /* CONFIG_APUS */
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/smplock.h linux/include/asm-ppc/smplock.h
--- v2.3.17/linux/include/asm-ppc/smplock.h	Mon Aug  3 12:28:20 1998
+++ linux/include/asm-ppc/smplock.h	Wed Sep  8 11:54:14 1999
@@ -4,7 +4,7 @@
  * Default SMP lock implementation
  */
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.3.17/linux/include/asm-ppc/softirq.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-ppc/softirq.h	Wed Sep  8 10:59:07 1999
@@ -54,19 +54,23 @@
 /* These are for the IRQs testing the lock */
 static inline int softirq_trylock(int cpu)
 {
-	if (!test_and_set_bit(0,&global_bh_count)) {
-		if (atomic_read(&global_bh_lock) &&
-		    ppc_local_bh_count[cpu] == 0) {
-			++ppc_local_bh_count[cpu];
-			return 1;
+	if (ppc_local_bh_count[cpu] == 0) {
+		ppc_local_bh_count[cpu] = 1;
+		if (!test_and_set_bit(0,&global_bh_count)) {
+			mb();
+			if (atomic_read(&global_bh_lock) == 0)
+				return 1;
+			clear_bit(0,&global_bh_count);
 		}
-		clear_bit(0,&global_bh_count);
+		ppc_local_bh_count[cpu] = 0;
+		mb();
 	}
 	return 0;
 }
 
 static inline void softirq_endlock(int cpu)
 {
+	mb();
 	ppc_local_bh_count[cpu]--;
 	clear_bit(0,&global_bh_count);
 }
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h
--- v2.3.17/linux/include/asm-ppc/spinlock.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/spinlock.h	Wed Sep  8 12:01:38 1999
@@ -1,79 +1,6 @@
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
-#ifndef __SMP__
-/*
- * Your basic spinlocks, allowing only a single CPU anywhere
- *
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-#endif
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		(void)(lock)	/* Avoid warnings about unused variable */
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-#define spin_lock_irq(lock)	cli()
-#define spin_unlock_irq(lock)	sti()
-#define spin_lock_bh(lock)	local_bh_disable()
-#define spin_unlock_bh(lock)	local_bh_enable()
-#define spin_lock_irqsave(lock, flags) \
-	do { save_flags(flags); cli(); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags) \
-	restore_flags(flags)
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- *
- * Gcc-2.7.x has a nasty bug with empty initializers.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { }
-#else
-  typedef struct { int gcc_is_buggy; } rwlock_t;
-  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
-#endif
-
-#define read_lock(lock)		(void)(lock)	/* Avoid warnings about unused variable */
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	(void)(lock)	/* Likewise */
-#define write_unlock(lock)	do { } while(0)
-#define read_lock_irq(lock)	cli()
-#define read_unlock_irq(lock)	sti()
-#define write_lock_irq(lock)	cli()
-#define write_unlock_irq(lock)	sti()
-#define read_lock_bh(lock)	local_bh_disable()
-#define read_unlock_bh(lock)	local_bh_enable()
-#define write_lock_bh(lock)	local_bh_disable()
-#define write_unlock_bh(lock)	local_bh_enable()
-
-#define read_lock_irqsave(lock, flags)	\
-	do { save_flags(flags); cli(); } while (0)
-#define read_unlock_irqrestore(lock, flags) \
-	restore_flags(flags)
-#define write_lock_irqsave(lock, flags)	\
-	do { save_flags(flags); cli(); } while (0)
-#define write_unlock_irqrestore(lock, flags) \
-	restore_flags(flags)
-
-#else /* __SMP__ */
-
 /* Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
  *
@@ -139,22 +66,4 @@
 #define write_unlock(rw)	_write_unlock(rw)
 #define read_unlock(rw)		_read_unlock(rw)
 
-#define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
-#define read_lock_bh(lock)	do { local_bh_disable(); read_lock(lock); } while (0)
-#define read_unlock_irq(lock)	do { read_unlock(lock); __sti(); } while (0)
-#define read_unlock_bh(lock)	do { read_unlock(lock); local_bh_enable(); } while (0)
-#define write_lock_irq(lock)	do { __cli(); write_lock(lock); } while (0)
-#define write_lock_bh(lock)	do { local_bh_disable(); write_lock(lock); } while(0)
-#define write_unlock_irq(lock)	do { write_unlock(lock); __sti(); } while (0)
-#define write_unlock_bh(lock)	do { write_unlock(lock); local_bh_enable(); } while(0)
-#define read_lock_irqsave(lock, flags)	\
-	do { __save_flags(flags); __cli(); read_lock(lock); } while (0)
-#define read_unlock_irqrestore(lock, flags) \
-	do { read_unlock(lock); __restore_flags(flags); } while (0)
-#define write_lock_irqsave(lock, flags)	\
-	do { __save_flags(flags); __cli(); write_lock(lock); } while (0)
-#define write_unlock_irqrestore(lock, flags) \
-	do { write_unlock(lock); __restore_flags(flags); } while (0)
-
-#endif /* SMP */
 #endif /* __ASM_SPINLOCK_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.3.17/linux/include/asm-ppc/system.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/system.h	Wed Sep  8 10:59:07 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: system.h,v 1.47 1999/08/22 12:31:08 paulus Exp $
+ * $Id: system.h,v 1.48 1999/09/05 11:56:40 paulus Exp $
  *
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  */
@@ -31,6 +31,10 @@
 #define mb()  __asm__ __volatile__ ("sync" : : : "memory")
 #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
 #define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")
+
+#define set_mb(var, value)	do { var = value; mb(); } while (0)
+#define set_rmb(var, value)	do { var = value; rmb(); } while (0)
+#define set_wmb(var, value)	do { var = value; wmb(); } while (0)
 
 extern void xmon_irq(int, void *, struct pt_regs *);
 extern void xmon(struct pt_regs *excp);
diff -u --recursive --new-file v2.3.17/linux/include/asm-sh/bugs.h linux/include/asm-sh/bugs.h
--- v2.3.17/linux/include/asm-sh/bugs.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-sh/bugs.h	Wed Sep  8 11:20:42 1999
@@ -14,7 +14,7 @@
 
 #include <asm/processor.h>
 
-__initfunc(static void check_bugs(void))
+static void __init check_bugs(void)
 {
 }
 #endif /* __ASM_SH_BUGS_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-sh/semaphore.h linux/include/asm-sh/semaphore.h
--- v2.3.17/linux/include/asm-sh/semaphore.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/semaphore.h	Wed Sep  8 11:54:14 1999
@@ -12,9 +12,10 @@
  *
  */
 
+#include <linux/spinlock.h>
+
 #include <asm/system.h>
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
 
 struct semaphore {
 	atomic_t count;
diff -u --recursive --new-file v2.3.17/linux/include/asm-sh/spinlock.h linux/include/asm-sh/spinlock.h
--- v2.3.17/linux/include/asm-sh/spinlock.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/spinlock.h	Wed Sep  8 12:01:38 1999
@@ -1,108 +1,6 @@
 #ifndef __ASM_SH_SPINLOCK_H
 #define __ASM_SH_SPINLOCK_H
 
-/*
- * These are the generic versions of the spinlocks
- * and read-write locks.. We should actually do a
- * <linux/spinlock.h> with all of this. Oh, well.
- */
-#define spin_lock_irqsave(lock, flags)		do { local_irq_save(flags);       spin_lock(lock); } while (0)
-#define spin_lock_irq(lock)			do { local_irq_disable();         spin_lock(lock); } while (0)
-#define spin_lock_bh(lock)			do { local_bh_disable();          spin_lock(lock); } while (0)
-
-#define read_lock_irqsave(lock, flags)		do { local_irq_save(flags);       read_lock(lock); } while (0)
-#define read_lock_irq(lock)			do { local_irq_disable();         read_lock(lock); } while (0)
-#define read_lock_bh(lock)			do { local_bh_disable();          read_lock(lock); } while (0)
-
-#define write_lock_irqsave(lock, flags)		do { local_irq_save(flags);      write_lock(lock); } while (0)
-#define write_lock_irq(lock)			do { local_irq_disable();        write_lock(lock); } while (0)
-#define write_lock_bh(lock)			do { local_bh_disable();         write_lock(lock); } while (0)
-
-#define spin_unlock_irqrestore(lock, flags)	do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
-#define spin_unlock_irq(lock)			do { spin_unlock(lock);  local_irq_enable();       } while (0)
-#define spin_unlock_bh(lock)			do { spin_unlock(lock);  local_bh_enable();        } while (0)
-
-#define read_unlock_irqrestore(lock, flags)	do { read_unlock(lock);  local_irq_restore(flags); } while (0)
-#define read_unlock_irq(lock)			do { read_unlock(lock);  local_irq_enable();       } while (0)
-#define read_unlock_bh(lock)			do { read_unlock(lock);  local_bh_enable();        } while (0)
-
-#define write_unlock_irqrestore(lock, flags)	do { write_unlock(lock); local_irq_restore(flags); } while (0)
-#define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
-#define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
-
-#ifndef __SMP__
-
-#define DEBUG_SPINLOCKS	0	/* 0 == no debugging, 1 == maintain lock state, 2 == full debug */
-
-#if (DEBUG_SPINLOCKS < 1)
-
-/*
- * Your basic spinlocks, allowing only a single CPU anywhere
- */
-typedef struct { } spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-
-#elif (DEBUG_SPINLOCKS < 2)
-
-typedef struct {
-	volatile unsigned int lock;
-} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
-
-#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
-#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
-
-#define spin_lock(x)		do { (x)->lock = 1; } while (0)
-#define spin_unlock_wait(x)	do { } while (0)
-#define spin_unlock(x)		do { (x)->lock = 0; } while (0)
-
-#else /* (DEBUG_SPINLOCKS >= 2) */
-
-typedef struct {
-	volatile unsigned int lock;
-	volatile unsigned int babble;
-	const char *module;
-} spinlock_t;
-#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
-
-#include <linux/kernel.h>
-
-#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
-#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
-
-#define spin_lock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
-#define spin_unlock_wait(x)	do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
-#define spin_unlock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
-
-#endif	/* DEBUG_SPINLOCKS */
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { }
-
-#define read_lock(lock)		(void)(lock) /* Not "unused variable". */
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	(void)(lock) /* Not "unused variable". */
-#define write_unlock(lock)	do { } while(0)
-
-#else
-
 #error "No SMP on SH"
 
-#endif /* SMP */
 #endif /* __ASM_SH_SPINLOCK_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h
--- v2.3.17/linux/include/asm-sparc/dma.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc/dma.h	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.30 1999/08/08 14:03:37 shadow Exp $
+/* $Id: dma.h,v 1.31 1999/09/10 10:44:15 davem Exp $
  * include/asm-sparc/dma.h
  *
  * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -16,7 +16,7 @@
 #include <asm/delay.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t  dma_spin_lock;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h
--- v2.3.17/linux/include/asm-sparc/hardirq.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc/hardirq.h	Wed Sep  8 11:55:45 1999
@@ -29,7 +29,7 @@
 #else
 
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/smp.h>
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/io-unit.h linux/include/asm-sparc/io-unit.h
--- v2.3.17/linux/include/asm-sparc/io-unit.h	Wed Mar 10 16:53:37 1999
+++ linux/include/asm-sparc/io-unit.h	Wed Sep  8 11:54:14 1999
@@ -5,8 +5,8 @@
 #ifndef _SPARC_IO_UNIT_H
 #define _SPARC_IO_UNIT_H
 
+#include <linux/spinlock.h>
 #include <asm/page.h>
-#include <asm/spinlock.h>
 #include <asm/pgtable.h>
 
 /* The io-unit handles all virtual to physical address translations
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/mostek.h linux/include/asm-sparc/mostek.h
--- v2.3.17/linux/include/asm-sparc/mostek.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc/mostek.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: mostek.h,v 1.11 1999/08/30 10:14:32 davem Exp $
+/* $Id: mostek.h,v 1.12 1999/08/31 18:51:41 davem Exp $
  * mostek.h:  Describes the various Mostek time of day clock registers.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -93,14 +93,14 @@
 #define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
 
 /* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(regs->var & MSTK_ ## mask ## _MASK))
-#define MSTK_SET(regs,var,value,mask) do { regs->var &= ~(MSTK_ ## mask ## _MASK); regs->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
+#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK))
+#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
 
 /* Macros to make register access easier on our fingers. These give you
  * the decimal value of the register requested if applicable. You pass
  * the a pointer to a 'struct mostek48t02'.
  */
-#define	MSTK_REG_CREG(regs)	(regs->creg)
+#define	MSTK_REG_CREG(regs)	(((struct mostek48t02 *)regs)->creg)
 #define	MSTK_REG_SEC(regs)	MSTK_GET(regs,sec,SEC)
 #define	MSTK_REG_MIN(regs)	MSTK_GET(regs,min,MIN)
 #define	MSTK_REG_HOUR(regs)	MSTK_GET(regs,hour,HOUR)
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h
--- v2.3.17/linux/include/asm-sparc/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc/pci.h	Wed Sep  8 11:14:32 1999
@@ -0,0 +1,10 @@
+#ifndef __SPARC_PCI_H
+#define __SPARC_PCI_H
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+ * already-configured bus numbers - to be used for buggy BIOSes
+ * or architectures with incomplete PCI setup by the loader.
+ */
+#define pcibios_assign_all_busses()	0
+
+#endif /* __SPARC_PCI_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.3.17/linux/include/asm-sparc/pgtable.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc/pgtable.h	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.81 1999/06/27 00:38:28 davem Exp $ */
+/* $Id: pgtable.h,v 1.82 1999/09/10 10:44:21 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -11,6 +11,7 @@
 
 #include <linux/mm.h>
 #include <linux/config.h>
+#include <linux/spinlock.h>
 #include <asm/asi.h>
 #ifdef CONFIG_SUN4
 #include <asm/pgtsun4.h>
@@ -22,7 +23,6 @@
 #include <asm/oplib.h>
 #include <asm/sbus.h>
 #include <asm/btfixup.h>
-#include <asm/spinlock.h>
 
 extern void load_mmu(void);
 extern int io_remap_page_range(unsigned long from, unsigned long to,
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h
--- v2.3.17/linux/include/asm-sparc/sigcontext.h	Tue Oct 27 09:52:21 1998
+++ linux/include/asm-sparc/sigcontext.h	Wed Sep  8 11:14:32 1999
@@ -1,18 +1,14 @@
-/* $Id: sigcontext.h,v 1.13 1998/10/06 09:28:35 jj Exp $ */
+/* $Id: sigcontext.h,v 1.14 1999/09/06 08:22:05 jj Exp $ */
 #ifndef __SPARC_SIGCONTEXT_H
 #define __SPARC_SIGCONTEXT_H
 
+#ifdef __KERNEL__
 #include <asm/ptrace.h>
-
-#define SUNOS_MAXWIN   31
+#endif
 
 #ifndef __ASSEMBLY__
 
-/* SunOS system call sigstack() uses this arg. */
-struct sunos_sigstack {
-	unsigned long sig_sp;
-	int onstack_flag;
-};
+#define __SUNOS_MAXWIN   31
 
 /* This is what SunOS does, so shall I. */
 struct sigcontext {
@@ -31,14 +27,23 @@
 	int sigc_oswins;       /* outstanding windows */
 
 	/* stack ptrs for each regwin buf */
-	char *sigc_spbuf[SUNOS_MAXWIN];
+	char *sigc_spbuf[__SUNOS_MAXWIN];
 
 	/* Windows to restore after signal */
-	struct reg_window sigc_wbuf[SUNOS_MAXWIN];
+	struct {
+		unsigned long	locals[8];
+		unsigned long	ins[8];
+	} sigc_wbuf[__SUNOS_MAXWIN];
 };
 
 typedef struct {
-	struct pt_regs	si_regs;
+	struct {
+		unsigned long psr;
+		unsigned long pc;
+		unsigned long npc;
+		unsigned long y;
+		unsigned long u_regs[16]; /* globals and ins */
+	}		si_regs;
 	int		si_mask;
 } __siginfo_t;
 
@@ -52,6 +57,8 @@
 	} si_fpqueue [16];
 } __siginfo_fpu_t;
 
+#ifdef __KERNEL__
+
 /* This magic should be in g_upper[0] for all upper parts
    to be valid.
    This is generated by sparc64 only, but for 32bit processes,
@@ -61,6 +68,8 @@
 	unsigned   int g_upper[8];
 	unsigned   int o_upper[8];
 } siginfo_extra_v8plus_t;
+
+#endif
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/signal.h linux/include/asm-sparc/signal.h
--- v2.3.17/linux/include/asm-sparc/signal.h	Tue Aug  4 16:03:35 1998
+++ linux/include/asm-sparc/signal.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: signal.h,v 1.34 1998/07/29 16:32:38 jj Exp $ */
+/* $Id: signal.h,v 1.35 1999/09/06 08:22:04 jj Exp $ */
 #ifndef _ASMSPARC_SIGNAL_H
 #define _ASMSPARC_SIGNAL_H
 
@@ -196,10 +196,12 @@
 	__new_sigset_t	sa_mask;
 };
 
+#ifdef __KERNEL__
 struct k_sigaction {
 	struct __new_sigaction	sa;
 	void			*ka_restorer;
 };
+#endif
 
 struct __old_sigaction {
 	__sighandler_t	sa_handler;
@@ -211,7 +213,7 @@
 typedef struct sigaltstack {
 	void		*ss_sp;
 	int		ss_flags;
-	__kernel_size_t	ss_size;
+	size_t		ss_size;
 } stack_t;
 
 #endif /* !(__ASSEMBLY__) */
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/smplock.h linux/include/asm-sparc/smplock.h
--- v2.3.17/linux/include/asm-sparc/smplock.h	Mon Aug  3 12:28:20 1998
+++ linux/include/asm-sparc/smplock.h	Wed Sep  8 11:54:14 1999
@@ -4,7 +4,7 @@
  * Default SMP lock implementation
  */
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h
--- v2.3.17/linux/include/asm-sparc/spinlock.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc/spinlock.h	Wed Sep  8 12:02:38 1999
@@ -10,57 +10,6 @@
 
 #ifndef __ASSEMBLY__
 
-#ifndef __SMP__
-
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED 0
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		do { } while(0)
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-#define spin_lock_irq(lock)	cli()
-#define spin_unlock_irq(lock)	sti()
-#define spin_lock_bh(lock)	local_bh_disable()
-#define spin_unlock_bh(lock)	local_bh_enable()
-
-#define spin_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define spin_unlock_irqrestore(lock, flags)	restore_flags(flags)
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-typedef struct { volatile unsigned int lock; } rwlock_t;
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
-
-#define read_lock(lock)		do { } while(0)
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	do { } while(0)
-#define write_unlock(lock)	do { } while(0)
-#define read_lock_irq(lock)	cli()
-#define read_unlock_irq(lock)	sti()
-#define write_lock_irq(lock)	cli()
-#define write_unlock_irq(lock)	sti()
-#define read_lock_bh(lock)	local_bh_disable()
-#define read_unlock_bh(lock)	local_bh_enable()
-#define write_lock_bh(lock)	local_bh_disable()
-#define write_unlock_bh(lock)	local_bh_enable()
-
-#define read_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define read_unlock_irqrestore(lock, flags)	restore_flags(flags)
-#define write_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define write_unlock_irqrestore(lock, flags)	restore_flags(flags)
-
-#else /* !(__SMP__) */
-
 #include <asm/psr.h>
 
 /* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */
@@ -370,8 +319,6 @@
 	do { write_unlock(lock); __restore_flags(flags); } while (0)
 
 #endif /* SPIN_LOCK_DEBUG */
-
-#endif /* __SMP__ */
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.3.17/linux/include/asm-sparc/system.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc/system.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.74 1999/05/08 03:03:14 davem Exp $ */
+/* $Id: system.h,v 1.75 1999/09/01 08:06:08 davem Exp $ */
 #include <linux/config.h>
 
 #ifndef __SPARC_SYSTEM_H
@@ -309,6 +309,9 @@
 #define mb()	__asm__ __volatile__ ("" : : : "memory")
 #define rmb()	mb()
 #define wmb()	mb()
+#define set_mb(__var, __value)  do { __var = __value; mb(); } while(0)
+#define set_rmb(__var, __value) set_mb(__var, __value)
+#define set_wmb(__var, __value) set_mb(__var, __value)
 
 #define nop() __asm__ __volatile__ ("nop");
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h
--- v2.3.17/linux/include/asm-sparc64/dma.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-sparc64/dma.h	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.14 1999/08/30 10:14:36 davem Exp $
+/* $Id: dma.h,v 1.16 1999/09/10 10:44:32 davem Exp $
  * include/asm-sparc64/dma.h
  *
  * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
@@ -10,11 +10,11 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/spinlock.h>
 
 #include <asm/sbus.h>
 #include <asm/delay.h>
 #include <asm/oplib.h>
-#include <asm/spinlock.h>
 
 extern spinlock_t  dma_spin_lock;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.3.17/linux/include/asm-sparc64/hardirq.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-sparc64/hardirq.h	Wed Sep  8 11:55:45 1999
@@ -33,7 +33,7 @@
 #else /* (__SMP__) */
 
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/smp.h>
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- v2.3.17/linux/include/asm-sparc64/io.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/io.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.21 1999/08/30 10:14:44 davem Exp $ */
+/* $Id: io.h,v 1.24 1999/09/06 01:17:54 davem Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
@@ -16,9 +16,6 @@
 
 #define PCI_DVMA_HASHSZ	256
 
-extern unsigned long pci_dvma_offset;
-extern unsigned long pci_dvma_mask;
-
 extern unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ];
 extern unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ];
 
@@ -49,11 +46,13 @@
 #define virt_to_bus virt_to_phys
 #define bus_to_virt phys_to_virt
 
-extern __inline__ unsigned long bus_dvma_to_mem(unsigned long vaddr)
-{
-	return vaddr & pci_dvma_mask;
-}
+/* Different PCI controllers we support have their PCI MEM space
+ * mapped to an either 2GB (Psycho) or 4GB (Sabre) aligned area,
+ * so need to chop off the top 33 or 32 bits.
+ */
+extern unsigned long pci_memspace_mask;
 
+#define bus_dvma_to_mem(__vaddr) ((__vaddr) & pci_memspace_mask)
 
 extern __inline__ unsigned int inb(unsigned long addr)
 {
@@ -120,12 +119,66 @@
 extern void insl(unsigned long addr, void *dst, unsigned long count);
 
 /* Memory functions, same as I/O accesses on Ultra. */
-#define readb(addr)		inb((unsigned long)(addr))
-#define readw(addr)		inw((unsigned long)(addr))
-#define readl(addr)		inl((unsigned long)(addr))
-#define writeb(b, addr)		outb((b), (unsigned long)(addr))
-#define writew(w, addr)		outw((w), (unsigned long)(addr))
-#define writel(l, addr)		outl((l), (unsigned long)(addr))
+extern __inline__ unsigned int _readb(unsigned long addr)
+{
+	unsigned int ret;
+
+	__asm__ __volatile__("lduba [%1] %2, %0"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L));
+
+	return ret;
+}
+
+extern __inline__ unsigned int _readw(unsigned long addr)
+{
+	unsigned int ret;
+
+	__asm__ __volatile__("lduha [%1] %2, %0"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L));
+
+	return ret;
+}
+
+extern __inline__ unsigned int _readl(unsigned long addr)
+{
+	unsigned int ret;
+
+	__asm__ __volatile__("lduwa [%1] %2, %0"
+			     : "=r" (ret)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L));
+
+	return ret;
+}
+
+extern __inline__ void _writeb(unsigned char b, unsigned long addr)
+{
+	__asm__ __volatile__("stba %0, [%1] %2"
+			     : /* no outputs */
+			     : "r" (b), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L));
+}
+
+extern __inline__ void _writew(unsigned short w, unsigned long addr)
+{
+	__asm__ __volatile__("stha %0, [%1] %2"
+			     : /* no outputs */
+			     : "r" (w), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L));
+}
+
+extern __inline__ void _writel(unsigned int l, unsigned long addr)
+{
+	__asm__ __volatile__("stwa %0, [%1] %2"
+			     : /* no outputs */
+			     : "r" (l), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L));
+}
+
+#define readb(__addr)		(_readb((unsigned long)(__addr)))
+#define readw(__addr)		(_readw((unsigned long)(__addr)))
+#define readl(__addr)		(_readl((unsigned long)(__addr)))
+#define writeb(__b, __addr)	(_writeb((__b), (unsigned long)(__addr)))
+#define writew(__w, __addr)	(_writew((__w), (unsigned long)(__addr)))
+#define writel(__l, __addr)	(_writel((__l), (unsigned long)(__addr)))
 
 /*
  * Memcpy to/from I/O space is just a regular memory operation on
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/iommu.h linux/include/asm-sparc64/iommu.h
--- v2.3.17/linux/include/asm-sparc64/iommu.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/iommu.h	Wed Sep  8 11:54:14 1999
@@ -5,9 +5,9 @@
 #ifndef _SPARC64_IOMMU_H
 #define _SPARC64_IOMMU_H
 
+#include <linux/spinlock.h>
 #include <asm/page.h>
 #include <asm/sysio.h>
-#include <asm/spinlock.h>
 
 /* The iommu handles all virtual to physical address translations
  * that occur between the SYSIO and physical memory.  Access by
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h
--- v2.3.17/linux/include/asm-sparc64/irq.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/irq.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.15 1999/08/30 10:14:48 davem Exp $
+/* $Id: irq.h,v 1.16 1999/09/06 01:17:52 davem Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -94,6 +94,7 @@
 #define NR_IRQS    15
 
 extern void disable_irq(unsigned int);
+#define disable_irq_nosync disable_irq
 extern void enable_irq(unsigned int);
 extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *),
 			unsigned long *);
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.3.17/linux/include/asm-sparc64/mmu_context.h	Mon Aug  2 22:07:16 1999
+++ linux/include/asm-sparc64/mmu_context.h	Fri Sep 10 11:06:19 1999
@@ -1,12 +1,12 @@
-/* $Id: mmu_context.h,v 1.39 1999/08/02 08:39:57 davem Exp $ */
+/* $Id: mmu_context.h,v 1.40 1999/09/10 10:44:37 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
 /* Derived heavily from Linus's Alpha/AXP ASN code... */
 
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/spitfire.h>
-#include <asm/spinlock.h>
 
 #ifndef __ASSEMBLY__
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h
--- v2.3.17/linux/include/asm-sparc64/oplib.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc64/oplib.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.10 1998/12/18 10:02:03 davem Exp $
+/* $Id: oplib.h,v 1.11 1999/08/31 19:25:49 davem Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -205,7 +205,8 @@
 /* MMU and memory related OBP interfaces. */
 
 /* Get unique string identifying SIMM at given physical address. */
-extern int prom_getunumber(unsigned long phys_lo, unsigned long phys_hi,
+extern int prom_getunumber(int syndrome_code,
+			   unsigned long phys_addr,
 			   char *buf, int buflen);
 
 /* Retain physical memory to the caller across soft resets. */
@@ -336,6 +337,7 @@
 #define P1275_ARG_OUT_32B		3
 #define P1275_ARG_IN_FUNCTION		4
 #define P1275_ARG_IN_BUF		5
+#define P1275_ARG_IN_64B		6
 
 #define P1275_IN(x) ((x) & 0xf)
 #define P1275_OUT(x) (((x) << 4) & 0xf0)
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h
--- v2.3.17/linux/include/asm-sparc64/pbm.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/pbm.h	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: pbm.h,v 1.17 1999/08/30 10:14:54 davem Exp $
+/* $Id: pbm.h,v 1.18 1999/09/10 10:44:40 davem Exp $
  * pbm.h: UltraSparc PCI controller software state.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -10,11 +10,11 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/oplib.h>
-#include <asm/spinlock.h>
 
 /* The abstraction used here is that there are PCI controllers,
  * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/pci.h linux/include/asm-sparc64/pci.h
--- v2.3.17/linux/include/asm-sparc64/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/pci.h	Wed Sep  8 11:14:32 1999
@@ -0,0 +1,44 @@
+#ifndef __SPARC64_PCI_H
+#define __SPARC64_PCI_H
+
+#include <asm/scatterlist.h>
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+ * already-configured bus numbers - to be used for buggy BIOSes
+ * or architectures with incomplete PCI setup by the loader.
+ */
+#define pcibios_assign_all_busses()	0
+
+/* Map kernel buffer using consistant mode DMA for PCI device.
+ * Returns a 32-bit PCI DMA address.
+ */
+extern u32 pci_map_consistant(struct pci_dev *, void *, int);
+
+/* Unmap a consistant DMA translation. */
+extern void pci_unmap_consistant(struct pci_dev *, u32, int);
+
+/* Map a single buffer for PCI DMA in streaming mode. */
+extern u32 pci_map_single(struct pci_dev *, void *, int);
+
+/* Unmap a single streaming mode DMA translation. */
+extern void pci_unmap_single(struct pci_dev *, u32, int);
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for PCI DMA.
+ */
+extern void pci_map_sg(struct pci_dev *, struct scatterlist *, int);
+
+/* Unmap a set of streaming mode DMA translations. */
+extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int);
+
+/* Make physical memory consistant for a single
+ * streaming mode DMA translation after a transfer.
+ */
+extern void pci_dma_sync_single(struct pci_dev *, u32, int);
+
+/* Make physical memory consistant for a set of streaming
+ * mode DMA translations after a transfer.
+ */
+extern void pci_dma_sync_sg(struct pci_dev *, struct scatterlist *, int);
+
+#endif /* __SPARC64_PCI_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/reg.h linux/include/asm-sparc64/reg.h
--- v2.3.17/linux/include/asm-sparc64/reg.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/reg.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: reg.h,v 1.5 1999/08/17 17:52:32 jj Exp $
+/* $Id: reg.h,v 1.6 1999/09/06 08:22:10 jj Exp $
  * linux/asm-sparc64/reg.h
  * Layout of the registers as expected by gdb on the Sparc
  * we should replace the user.h definitions with those in
@@ -51,5 +51,6 @@
 };
 
 #define fpu_regs  f_fpstatus.fpu_fr
+#define fpu_fsr   f_fpstatus.Fpu_fsr
 
 #endif /* __SPARC64_REG_H */
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/sigcontext.h linux/include/asm-sparc64/sigcontext.h
--- v2.3.17/linux/include/asm-sparc64/sigcontext.h	Tue Oct 27 09:52:21 1998
+++ linux/include/asm-sparc64/sigcontext.h	Wed Sep  8 11:14:32 1999
@@ -1,20 +1,18 @@
-/* $Id: sigcontext.h,v 1.11 1998/10/06 09:28:37 jj Exp $ */
+/* $Id: sigcontext.h,v 1.12 1999/09/06 08:22:09 jj Exp $ */
 #ifndef __SPARC64_SIGCONTEXT_H
 #define __SPARC64_SIGCONTEXT_H
 
+#ifdef __KERNEL__
 #include <asm/ptrace.h>
-
-#define SUNOS_MAXWIN   31
+#endif
 
 #ifndef __ASSEMBLY__
 
-/* SunOS system call sigstack() uses this arg. */
-struct sunos_sigstack {
-	unsigned int sig_sp;
-	int onstack_flag;
-};
+#ifdef __KERNEL__
+
+#define __SUNOS_MAXWIN   31
 
-/* This is what SunOS does, so shall I. */
+/* This is what SunOS does, so shall I unless we use new 32bit signals or rt signals. */
 struct sigcontext32 {
 	int sigc_onstack;      /* state to restore */
 	int sigc_mask;         /* sigmask to restore */
@@ -31,44 +29,30 @@
 	int sigc_oswins;       /* outstanding windows */
 
 	/* stack ptrs for each regwin buf */
-	unsigned sigc_spbuf[SUNOS_MAXWIN];
+	unsigned sigc_spbuf[__SUNOS_MAXWIN];
 
 	/* Windows to restore after signal */
-	struct reg_window32 sigc_wbuf[SUNOS_MAXWIN];
+	struct reg_window32 sigc_wbuf[__SUNOS_MAXWIN];
 };
 
-/* This is what SunOS doesn't, so we have to write this alone. */
-struct sigcontext {
-	int sigc_onstack;      /* state to restore */
-	int sigc_mask;         /* sigmask to restore */
-	unsigned long sigc_sp;   /* stack pointer */
-	unsigned long sigc_pc;   /* program counter */
-	unsigned long sigc_npc;  /* next program counter */
-	unsigned long sigc_psr;  /* for condition codes etc */
-	unsigned long sigc_g1;   /* User uses these two registers */
-	unsigned long sigc_o0;   /* within the trampoline code. */
-
-	/* Now comes information regarding the users window set
-	 * at the time of the signal.
-	 */
-	int sigc_oswins;       /* outstanding windows */
+#endif
 
-	/* stack ptrs for each regwin buf */
-	char *sigc_spbuf[SUNOS_MAXWIN];
+#ifdef __KERNEL__
 
-	/* Windows to restore after signal */
-	struct reg_window sigc_wbuf[SUNOS_MAXWIN];
-};
+/* This is what we use for 32bit new non-rt signals. */
 
 typedef struct {
-	struct pt_regs32	si_regs;
+	struct {
+		unsigned int psr;
+		unsigned int pc;
+		unsigned int npc;
+		unsigned int y;
+		unsigned int u_regs[16]; /* globals and ins */
+	}			si_regs;
 	int			si_mask;
 } __siginfo32_t;
 
-typedef struct {
-	struct     pt_regs si_regs;
-	long	   si_mask;
-} __siginfo_t;
+#endif
 
 typedef struct {
 	unsigned   int si_float_regs [64];
@@ -77,6 +61,30 @@
 	unsigned   long si_fprs;
 } __siginfo_fpu_t;
 
+/* This is what SunOS doesn't, so we have to write this alone
+   and do it properly. */
+struct sigcontext {
+	/* The size of this array has to match SI_MAX_SIZE from siginfo.h */
+	char			sigc_info[128];
+	struct {
+		unsigned long	u_regs[16]; /* globals and ins */
+		unsigned long	tstate;
+		unsigned long	tpc;
+		unsigned long	tnpc;
+		unsigned int	y;
+		unsigned int	fprs;
+	}			sigc_regs;
+	__siginfo_fpu_t *	sigc_fpu_save;
+	struct {
+		void	*	ss_sp;
+		int		ss_flags;
+		unsigned long	ss_size;
+	}			sigc_stack;
+	unsigned long		sigc_mask;
+};
+
+#ifdef __KERNEL__
+
 /* This magic should be in g_upper[0] for all upper parts
    to be valid.  */
 #define SIGINFO_EXTRA_V8PLUS_MAGIC	0x130e269
@@ -84,6 +92,8 @@
 	unsigned   int g_upper[8];
 	unsigned   int o_upper[8];
 } siginfo_extra_v8plus_t;
+
+#endif
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/signal.h linux/include/asm-sparc64/signal.h
--- v2.3.17/linux/include/asm-sparc64/signal.h	Tue Aug  4 16:03:35 1998
+++ linux/include/asm-sparc64/signal.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: signal.h,v 1.8 1998/07/29 16:32:39 jj Exp $ */
+/* $Id: signal.h,v 1.9 1999/09/06 08:22:11 jj Exp $ */
 #ifndef _ASMSPARC64_SIGNAL_H
 #define _ASMSPARC64_SIGNAL_H
 
@@ -196,7 +196,7 @@
 
 /* Type of a signal handler.  */
 #ifdef __KERNEL__
-typedef void (*__sighandler_t)(int, int, struct sigcontext *, char *);
+typedef void (*__sighandler_t)(int, struct sigcontext *);
 #else
 typedef void (*__sighandler_t)(int);
 #endif
@@ -219,10 +219,12 @@
 	__new_sigset_t32 	sa_mask;
 };
 
+#ifdef __KERNEL__
 struct k_sigaction {
 	struct __new_sigaction 	sa;
 	void			*ka_restorer;
 };
+#endif
 
 struct __old_sigaction {
 	__sighandler_t  	sa_handler;
@@ -239,16 +241,18 @@
 };
 
 typedef struct sigaltstack {
-       void 			*ss_sp;
-       int 			ss_flags;
-       __kernel_size_t 		ss_size;
+	void			*ss_sp;
+	int			ss_flags;
+	size_t			ss_size;
 } stack_t;
 
+#ifdef __KERNEL__
 typedef struct sigaltstack32 {
-       u32			ss_sp;
-       int 			ss_flags;
-       __kernel_size_t32 	ss_size;
+	u32			ss_sp;
+	int			ss_flags;
+	__kernel_size_t32	ss_size;
 } stack_t32;
+#endif
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/smplock.h linux/include/asm-sparc64/smplock.h
--- v2.3.17/linux/include/asm-sparc64/smplock.h	Tue Oct 27 09:52:21 1998
+++ linux/include/asm-sparc64/smplock.h	Wed Sep  8 11:54:14 1999
@@ -5,7 +5,7 @@
  */
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 extern spinlock_t kernel_flag;
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.3.17/linux/include/asm-sparc64/spinlock.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/spinlock.h	Fri Sep 10 11:06:19 1999
@@ -8,88 +8,6 @@
 
 #ifndef __ASSEMBLY__
 
-#ifndef __SMP__
-
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } spinlock_t;
-# define SPIN_LOCK_UNLOCKED (spinlock_t) { }
-#else
-  typedef unsigned char spinlock_t;
-# define SPIN_LOCK_UNLOCKED 0
-#endif
-
-#define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		(void)(lock)	/* Avoid warnings about unused variable */
-#define spin_trylock(lock)	(1)
-#define spin_unlock_wait(lock)	do { } while(0)
-#define spin_unlock(lock)	do { } while(0)
-#define spin_lock_irq(lock)	cli()
-#define spin_unlock_irq(lock)	sti()
-#define spin_lock_bh(lock) \
-do {	local_bh_count++; \
-	barrier(); \
-} while(0)
-#define spin_unlock_bh(lock) \
-do {	barrier(); \
-	local_bh_count--; \
-} while(0)
-
-#define spin_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define spin_unlock_irqrestore(lock, flags)	restore_flags(flags)
-
-/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
- *
- * NOTE! it is quite common to have readers in interrupts
- * but no interrupt writers. For those circumstances we
- * can "mix" irq-safe locks - any writer needs to get a
- * irq-safe write-lock, but readers can get non-irqsafe
- * read-locks.
- */
-#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
-  typedef struct { } rwlock_t;
-# define RW_LOCK_UNLOCKED (rwlock_t) { }
-#else
-  typedef unsigned int rwlock_t;
-# define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
-#endif
-
-#define read_lock(lock)		(void)(lock)	/* Avoid warnings about unused variable */
-#define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	(void)(lock)	/* Likewise */
-#define write_unlock(lock)	do { } while(0)
-#define read_lock_irq(lock)	cli()
-#define read_unlock_irq(lock)	sti()
-#define read_lock_bh(lock) \
-do {	local_bh_count++; \
-	barrier(); \
-} while(0)
-#define read_unlock_bh(lock) \
-do {	barrier(); \
-	local_bh_count--; \
-} while(0)
-
-#define write_lock_irq(lock)	cli()
-#define write_unlock_irq(lock)	sti()
-
-#define write_lock_bh(lock) \
-do {	local_bh_count++; \
-	barrier(); \
-} while(0)
- 
-#define write_unlock_bh(lock) \
-do {	barrier(); \
-	local_bh_count--; \
-} while(0)
-
-#define read_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define read_unlock_irqrestore(lock, flags)	restore_flags(flags)
-#define write_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define write_unlock_irqrestore(lock, flags)	restore_flags(flags)
-
-#else /* !(__SMP__) */
-
 /* To get debugging spinlocks which detect and catch
  * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
  * specific makefile and rebuild your kernel.
@@ -151,83 +69,12 @@
 extern __inline__ void spin_unlock(spinlock_t *lock)
 {
 	__asm__ __volatile__("membar	#StoreStore | #LoadStore\n\t"
-			     "stb	%%g0, [%0]\n\t"
-			     "membar	#StoreStore | #StoreLoad"
+			     "stb	%%g0, [%0]"
 			     : /* No outputs */
 			     : "r" (lock)
 			     : "memory");
 }
 
-extern __inline__ void spin_lock_irq(spinlock_t *lock)
-{
-	__asm__ __volatile__("
-	wrpr		%%g0, 15, %%pil
-1:	ldstub		[%0], %%g7
-	brnz,pn		%%g7, 2f
-	 membar		#StoreLoad | #StoreStore
-	.subsection	2
-2:	ldub		[%0], %%g7
-	brnz,pt		%%g7, 2b
-	 membar		#LoadLoad
-	b,a,pt		%%xcc, 1b
-	.previous
-"	: /* no outputs */
-	: "r" (lock)
-	: "g7", "memory");
-}
-
-extern __inline__ void spin_unlock_irq(spinlock_t *lock)
-{
-	__asm__ __volatile__("membar	#StoreStore | #LoadStore\n\t"
-			     "stb	%%g0, [%0]\n\t"
-			     "membar	#StoreStore | #StoreLoad\n\t"
-			     "wrpr	%%g0, 0x0, %%pil"
-			     : /* no outputs */
-			     : "r" (lock)
-			     : "memory");
-}
-
-#define spin_lock_bh(__lock)	\
-do {	local_bh_count++;	\
-	spin_lock(__lock);	\
-} while(0)
-
-#define spin_unlock_bh(__lock)		\
-do {	spin_unlock(__lock);		\
-	local_bh_count--;		\
-} while(0)
-
-#define spin_lock_irqsave(__lock, flags)			\
-do {	register spinlock_t *__lp asm("g1");			\
-	__lp = (__lock);					\
-	__asm__ __volatile__(					\
-	"\n	rdpr		%%pil, %0\n"			\
-	"	wrpr		%%g0, 15, %%pil\n"		\
-	"1:	ldstub		[%1], %%g7\n"			\
-	"	brnz,pn		%%g7, 2f\n"			\
-	"	 membar		#StoreLoad | #StoreStore\n"	\
-	"	.subsection	2\n"				\
-	"2:	ldub		[%1], %%g7\n"			\
-	"	brnz,pt		%%g7, 2b\n"			\
-	"	 membar		#LoadLoad\n"			\
-	"	b,a,pt		%%xcc, 1b\n"			\
-	"	.previous\n"					\
-	: "=&r" (flags)						\
-	: "r" (__lp)						\
-	: "g7", "memory");					\
-} while(0)
-
-extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
-{
-	__asm__ __volatile__("membar	#StoreStore | #LoadStore\n\t"
-			     "stb	%%g0, [%0]\n\t"
-			     "membar	#StoreStore | #StoreLoad\n\t"
-			     "wrpr	%1, 0x0, %%pil"
-			     : /* no outputs */
-			     : "r" (lock), "r" (flags)
-			     : "memory");
-}
-
 #else /* !(SPIN_LOCK_DEBUG) */
 
 typedef struct {
@@ -252,13 +99,7 @@
 
 #define spin_trylock(lp)	_spin_trylock(lp)
 #define spin_lock(lock)		_do_spin_lock(lock, "spin_lock")
-#define spin_lock_irq(lock)	do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
-#define spin_lock_bh(lock)	do { local_bh_count++; _do_spin_lock(lock, "spin_lock_bh"); } while(0)
-#define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0)
 #define spin_unlock(lock)	_do_spin_unlock(lock)
-#define spin_unlock_irq(lock)	do { _do_spin_unlock(lock); __sti(); } while(0)
-#define spin_unlock_bh(lock)	do { _do_spin_unlock(lock); local_bh_count--; } while(0)
-#define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0)
 
 #endif /* SPIN_LOCK_DEBUG */
 
@@ -305,24 +146,6 @@
 	  : "g2", "g3", "g5", "g7", "cc", "memory"); \
 } while(0)
 
-#define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
-#define read_unlock_irq(lock)	do { read_unlock(lock); __sti(); } while (0)
-#define read_lock_bh(lock)	do { local_bh_count++; read_lock(lock); } while (0)
-#define read_unlock_bh(lock)	do { read_unlock(lock); local_bh_count--; } while (0)
-#define write_lock_irq(lock)	do { __cli(); write_lock(lock); } while (0)
-#define write_unlock_irq(lock)	do { write_unlock(lock); __sti(); } while (0)
-#define write_lock_bh(lock)	do { local_bh_count++; write_lock(lock); } while (0)
-#define write_unlock_bh(lock)	do { write_unlock(lock); local_bh_count--; } while (0)
-
-#define read_lock_irqsave(lock, flags)	\
-	do { __save_and_cli(flags); read_lock(lock); } while (0)
-#define read_unlock_irqrestore(lock, flags) \
-	do { read_unlock(lock); __restore_flags(flags); } while (0)
-#define write_lock_irqsave(lock, flags)	\
-	do { __save_and_cli(flags); write_lock(lock); } while (0)
-#define write_unlock_irqrestore(lock, flags) \
-	do { write_unlock(lock); __restore_flags(flags); } while (0)
-
 #else /* !(SPIN_LOCK_DEBUG) */
 
 typedef struct {
@@ -343,9 +166,6 @@
 	_do_read_lock(lock, "read_lock"); \
 	__restore_flags(flags); \
 } while(0)
-#define read_lock_irq(lock)	do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0)
-#define read_lock_bh(lock)	do { local_bh_count++; _do_read_lock(lock, "read_lock_bh"); } while(0)
-#define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0)
 
 #define read_unlock(lock) \
 do {	unsigned long flags; \
@@ -353,9 +173,6 @@
 	_do_read_unlock(lock, "read_unlock"); \
 	__restore_flags(flags); \
 } while(0)
-#define read_unlock_irq(lock)	do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0)
-#define read_unlock_bh(lock)	do { _do_read_unlock(lock, "read_unlock_bh"); local_bh_count--; } while(0)
-#define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
 
 #define write_lock(lock) \
 do {	unsigned long flags; \
@@ -363,9 +180,6 @@
 	_do_write_lock(lock, "write_lock"); \
 	__restore_flags(flags); \
 } while(0)
-#define write_lock_irq(lock)	do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0)
-#define write_lock_bh(lock)	do { local_bh_count++; _do_write_lock(lock, "write_lock_bh"); } while(0)
-#define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0)
 
 #define write_unlock(lock) \
 do {	unsigned long flags; \
@@ -373,13 +187,8 @@
 	_do_write_unlock(lock); \
 	__restore_flags(flags); \
 } while(0)
-#define write_unlock_irq(lock)	do { _do_write_unlock(lock); __sti(); } while(0)
-#define write_unlock_bh(lock)	do { _do_write_unlock(lock); local_bh_count--; } while(0)
-#define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0)
 
 #endif /* SPIN_LOCK_DEBUG */
-
-#endif /* __SMP__ */
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.3.17/linux/include/asm-sparc64/system.h	Wed Aug  4 15:39:46 1999
+++ linux/include/asm-sparc64/system.h	Fri Sep 10 11:06:19 1999
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.53 1999/08/03 05:16:14 davem Exp $ */
+/* $Id: system.h,v 1.55 1999/09/10 10:44:44 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -63,9 +63,13 @@
 	retval; \
 })
 
-#define __save_flags(flags)	((flags) = getipl())
-#define __save_and_cli(flags)	((flags) = read_pil_and_cli())
-#define __restore_flags(flags)	setipl((flags))
+#define __save_flags(flags)		((flags) = getipl())
+#define __save_and_cli(flags)		((flags) = read_pil_and_cli())
+#define __restore_flags(flags)		setipl((flags))
+#define local_irq_disable()		__cli()
+#define local_irq_enable()		__sti()
+#define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_restore(flags)	__restore_flags(flags)
 
 #ifndef __SMP__
 #define cli() __cli()
@@ -97,6 +101,12 @@
 #define membar(type)	__asm__ __volatile__ ("membar " type : : : "memory");
 #define rmb()		membar("#LoadLoad | #LoadStore")
 #define wmb()		membar("#StoreLoad | #StoreStore")
+#define set_mb(__var, __value) \
+	do { __var = __value; membar("#StoreLoad | #StoreStore"); } while(0)
+#define set_rmb(__var, __value) \
+	do { __var = __value; membar("#StoreLoad"); } while(0)
+#define set_wmb(__var, __value) \
+	do { __var = __value; membar("#StoreStore"); } while(0)
 
 #define flushi(addr)	__asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
 
diff -u --recursive --new-file v2.3.17/linux/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h
--- v2.3.17/linux/include/asm-sparc64/ttable.h	Mon Aug  2 22:07:16 1999
+++ linux/include/asm-sparc64/ttable.h	Wed Sep  8 11:14:32 1999
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.12 1999/07/30 09:31:24 davem Exp $ */
+/* $Id: ttable.h,v 1.13 1999/08/31 19:25:50 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
@@ -54,6 +54,13 @@
 	 clr	%l6;					\
 	nop;
 	
+#define TRAPTL1_CEE			\
+	ldxa	[%g0] ASI_AFSR, %g1;	\
+	membar	#Sync;			\
+	stxa	%g1, [%g0] ASI_AFSR;	\
+	membar	#Sync;			\
+	retry; nop; nop; nop;
+
 #define TRAP_ARG(routine, arg)				\
 	sethi	%hi(109f), %g7;				\
 	ba,pt	%xcc, etrap;				\
diff -u --recursive --new-file v2.3.17/linux/include/linux/arequipa.h linux/include/linux/arequipa.h
--- v2.3.17/linux/include/linux/arequipa.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/arequipa.h	Wed Dec 31 16:00:00 1969
@@ -1,63 +0,0 @@
-/* arequipa.h - Arequipa interface definitions */
- 
-/* Written 1996-1998 by Jean-Michel Pittet and Werner Almesberger, EPFL ICA */
- 
-
-#ifndef _LINUX_AREQUIPA_H
-#define _LINUX_AREQUIPA_H
-
-#include <linux/atmioc.h>
-
-
-enum arequipa_msg_type { amt_invalid,amt_close,amt_sync };
-
-struct arequipa_msg {
-	enum arequipa_msg_type type;
-	void *ptr;
-};
-
-
-#define AREQUIPA_PRESET		_IO('a',ATMIOC_AREQUIPA)
-#define AREQUIPA_INCOMING	_IO('a',ATMIOC_AREQUIPA+1)
-#define AREQUIPA_EXPECT		_IO('a',ATMIOC_AREQUIPA+2)
-#define AREQUIPA_CLOSE		_IO('a',ATMIOC_AREQUIPA+3)
-#define AREQUIPA_CTRL		_IO('a',ATMIOC_AREQUIPA+4)
-/* #define AREQUIPA_CLS3RD	removed */
-#define AREQUIPA_SYNCREQ	_IO('a',ATMIOC_AREQUIPA+6)
-/* #define AREQUIPA_SYNCACK	removed */
-#define AREQUIPA_WORK		_IO('a',ATMIOC_AREQUIPA+8)
-#define AREQUIPA_RENEGOTIATE	_IO('a',ATMIOC_AREQUIPA+9)
-
-
-#ifdef __KERNEL__
-
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/ip.h>
-#include <linux/atm.h>
-#include <net/sock.h>
-
-
-extern struct atm_vcc *aqd; /* for net/atm/proc.c */
-/* extern struct rtable *arequipa_rt; - not needed; we use a local dcl instead*/
-extern struct net_device *arequipa_dev;
-
-int atm_init_arequipa(void);
-int arequipa_attach(struct socket *lower,struct sock *upper,
-    unsigned long generation);
-
-int arequipa_preset(struct socket *lower,struct sock *upper);
-int arequipa_expect(struct sock *upper,int on,int kmalloc_flags);
-int arequipa_incoming(struct socket *lower);
-int arequipa_close(struct sock *upper);
-int arequipa_renegotiate(struct sock *upper,struct atm_qos *u_qos);
-void arequipa_synchronize(void);
-void arequipa_work(void);
-
-int arequipad_attach(struct atm_vcc *vcc);
-
-
-#endif /* __KERNEL__ */
-
-#endif
diff -u --recursive --new-file v2.3.17/linux/include/linux/atm.h linux/include/linux/atm.h
--- v2.3.17/linux/include/linux/atm.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/atm.h	Thu Sep  9 22:21:29 1999
@@ -47,10 +47,17 @@
 #define ATM_AAL34	3		/* AAL3/4 (data) */
 #define ATM_AAL5	5		/* AAL5 (data) */
 
-/* socket option name coding functions */
+/*
+ * socket option name coding functions
+ *
+ * Note that __SO_ENCODE and __SO_LEVEL are somewhat a hack since the
+ * << 22 only reserves 9 bits for the level.  On some architectures
+ * SOL_SOCKET is 0xFFFF, so that's a bit of a problem
+ */
 
-#define __SO_ENCODE(l,n,t)	(((l) << 22) | ((n) << 16) | sizeof(t))
-#define __SO_LEVEL(c)		((c) >> 22)
+#define __SO_ENCODE(l,n,t)	((((l) & 0x1FF) << 22) | ((n) << 16) | \
+				sizeof(t))
+#define __SO_LEVEL_MATCH(c,m)	(((c) >> 22) == ((m) & 0x1FF))
 #define __SO_NUMBER(c)		(((c) >> 16) & 0x3f)
 #define __SO_SIZE(c)		((c) & 0x3fff)
 
@@ -67,6 +74,8 @@
 			    /* Quality of Service setting */
 #define SO_ATMSAP	__SO_ENCODE(SOL_ATM,3,struct atm_sap)
 			    /* Service Access Point */
+#define SO_ATMPVC	__SO_ENCODE(SOL_ATM,4,struct sockaddr_atmpvc)
+			    /* "PVC" address (also for SVCs); get only */
 
 /*
  * Note @@@: since the socket layers don't really distinguish the control and
diff -u --recursive --new-file v2.3.17/linux/include/linux/atm_tcp.h linux/include/linux/atm_tcp.h
--- v2.3.17/linux/include/linux/atm_tcp.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/atm_tcp.h	Wed Sep  8 11:14:32 1999
@@ -1,7 +1,7 @@
 /* atm_tcp.h - Driver-specific declarations of the ATMTCP driver (for use by
 	       driver-specific utilities) */
 
-/* Written 1997,1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1997-1999 by Werner Almesberger, EPFL LRC/ICA */
 
 
 #ifndef LINUX_ATM_TCP_H
@@ -14,7 +14,7 @@
 
 
 /*
- * All values are in network byte order
+ * All values in struct atmtcp_hdr are in network byte order
  */
 
 struct atmtcp_hdr {
@@ -23,12 +23,38 @@
 	uint32_t	length;		/* ... of data part */
 };
 
+/*
+ * All values in struct atmtcp_command are in host byte order
+ */
+
+#define ATMTCP_HDR_MAGIC	(~0)	/* this length indicates a command */
+#define ATMTCP_CTRL_OPEN	1	/* request/reply */
+#define ATMTCP_CTRL_CLOSE	2	/* request/reply */
+
+struct atmtcp_control {
+	struct atmtcp_hdr hdr;	/* must be first */
+	int		type;	/* message type; both directions */
+	unsigned long	vcc;	/* both directions */
+	struct sockaddr_atmpvc addr; /* suggested value from kernel */
+	struct atm_qos	qos;	/* both directions */
+	int result;		/* to kernel only */
+};
+
+/*
+ * Field usage:
+ * Messge type	dir.	hdr.v?i	type	addr	qos	vcc	result
+ * -----------  ----	------- ----	----	---	---	------
+ * OPEN		K->D	Y	Y	Y	Y	Y	0
+ * OPEN		D->K	-	Y	Y	Y	Y	Y
+ * CLOSE	K->D	-	-	Y	-	Y	0
+ * CLOSE	D->K	-	-	-	-	Y	Y
+ */
 
 #define SIOCSIFATMTCP	_IO('a',ATMIOC_ITF)	/* set ATMTCP mode */
 #define ATMTCP_CREATE	_IO('a',ATMIOC_ITF+14)	/* create persistent ATMTCP
 						   interface */
 #define ATMTCP_REMOVE	_IO('a',ATMIOC_ITF+15)	/* destroy persistent ATMTCP
-						   interface*/
+						   interface */
 
 
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.3.17/linux/include/linux/atmdev.h linux/include/linux/atmdev.h
--- v2.3.17/linux/include/linux/atmdev.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/atmdev.h	Thu Sep  9 22:21:29 1999
@@ -138,10 +138,6 @@
 #include <linux/proc_fs.h>
 #endif
 
-#ifdef CONFIG_AREQUIPA
-#include <net/sock.h> /* for struct sock */
-#endif
-
 
 #define ATM_VF_ADDR	1	/* Address is in use. Set by anybody, cleared
 				   by device driver. */
@@ -220,17 +216,11 @@
 	struct sk_buff_head listenq;
 	int		backlog_quota;	/* number of connection requests we */
 					/* can still accept */
-	int		reply;
+	int		reply;		/* also used by ATMTCP */
 	/* Multipoint part ------------------------------------------------- */
 	struct atm_vcc	*session;	/* session VCC descriptor */
 	/* Other stuff ----------------------------------------------------- */
 	void		*user_back;	/* user backlink - not touched */
-#ifdef CONFIG_AREQUIPA
-	struct sock	*upper;		/* our "master" */
-	struct socket	*sock;		/* back pointer to our own socket */
-	struct atm_vcc	*aq_next,*aq_prev; /* for consistency checks */
-	unsigned long	generation;	/* generation number */
-#endif
 };
 
 
@@ -325,14 +315,12 @@
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev);
 
 
-/* This is the algorithm used by alloc_skb
-
-   SHIT! It is fully illegal. If we could derive truesize
-   from another skb parameter, we would not create this variable.
-   Do not wonder, if allocating 5K skbm truesize will be > 8K.
+/*
+ * This is approximately the algorithm used by alloc_skb.
+ *
  */
 
-static __inline__ int atm_pdu2truesize(int pdu_size)
+static __inline__ int atm_guess_pdu2truesize(int pdu_size)
 {
 	return ((pdu_size+15) & ~15) + sizeof(struct sk_buff);
 }
@@ -351,7 +339,8 @@
 
 
 int atm_charge(struct atm_vcc *vcc,int truesize);
-void atm_return(struct atm_vcc *vcc,int truesize);
+struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
+    int gfp_flags);
 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci);
 int atm_pcr_goal(struct atm_trafprm *tp);
 
diff -u --recursive --new-file v2.3.17/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.3.17/linux/include/linux/blk.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/blk.h	Thu Sep  9 22:17:31 1999
@@ -4,8 +4,7 @@
 #include <linux/blkdev.h>
 #include <linux/locks.h>
 #include <linux/config.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 /*
  * Spinlock for protecting the request queue which
diff -u --recursive --new-file v2.3.17/linux/include/linux/cyclomx.h linux/include/linux/cyclomx.h
--- v2.3.17/linux/include/linux/cyclomx.h	Sun Aug 15 11:49:08 1999
+++ linux/include/linux/cyclomx.h	Wed Sep  8 11:55:45 1999
@@ -23,7 +23,7 @@
 
 #include <linux/config.h>
 #include <linux/wanrouter.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #ifdef	__KERNEL__
 /* Kernel Interface */
diff -u --recursive --new-file v2.3.17/linux/include/linux/hdlcdrv.h linux/include/linux/hdlcdrv.h
--- v2.3.17/linux/include/linux/hdlcdrv.h	Wed Aug 18 11:38:46 1999
+++ linux/include/linux/hdlcdrv.h	Wed Sep  8 11:55:45 1999
@@ -106,7 +106,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/if.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #define HDLCDRV_MAGIC      0x5ac6e778
 #define HDLCDRV_IFNAMELEN    6
diff -u --recursive --new-file v2.3.17/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.3.17/linux/include/linux/kernel.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/kernel.h	Fri Sep 10 08:26:38 1999
@@ -96,7 +96,7 @@
 	unsigned short procs;		/* Number of current processes */
 	unsigned long totalbig;		/* Total big memory size */
 	unsigned long freebig;		/* Available big memory size */
-	char _f[22-2*sizeof(long)];	/* Padding: libc5 uses this.. */
+	char _f[20-2*sizeof(long)];	/* Padding: libc5 uses this.. */
 };
 
 #endif
diff -u --recursive --new-file v2.3.17/linux/include/linux/netfilter.h linux/include/linux/netfilter.h
--- v2.3.17/linux/include/linux/netfilter.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/netfilter.h	Thu Sep  9 22:21:44 1999
@@ -57,23 +57,29 @@
 	int priority;
 };
 
-struct nf_setsockopt_ops
+struct nf_sockopt_ops
 {
 	struct list_head list;
 
 	int pf;
-	int optmin;
-	int optmax;
-	int (*fn)(int optval, void *user, unsigned int len);
+
+	/* Non-inclusive ranges: use 0/0/NULL to never get called. */
+	int set_optmin;
+	int set_optmax;
+	int (*set)(struct sock *sk, int optval, void *user, unsigned int len);
+
+	int get_optmin;
+	int get_optmax;
+	int (*get)(struct sock *sk, int optval, void *user, int *len);
 };
 
 /* Function to register/unregister hook points. */
 int nf_register_hook(struct nf_hook_ops *reg);
 void nf_unregister_hook(struct nf_hook_ops *reg);
 
-/* Functions to register setsockopt ranges (inclusive). */
-int nf_register_sockopt(struct nf_setsockopt_ops *reg);
-void nf_unregister_sockopt(struct nf_setsockopt_ops *reg);
+/* Functions to register get/setsockopt ranges (non-inclusive). */
+int nf_register_sockopt(struct nf_sockopt_ops *reg);
+void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
 
 extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
 
@@ -114,7 +120,10 @@
 		   __u32 packetcount, __u32 bytecount);
 
 /* Call setsockopt() */
-int nf_setsockopt(int pf, int optval, char *opt, unsigned int len);
+int nf_setsockopt(struct sock *sk, int pf, int optval, char *opt, 
+		  int len);
+int nf_getsockopt(struct sock *sk, int pf, int optval, char *opt,
+		  int *len);
 
 struct nf_wakeme
 {
diff -u --recursive --new-file v2.3.17/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.17/linux/include/linux/parport.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/parport.h	Thu Sep  9 22:18:21 1999
@@ -84,9 +84,9 @@
 #ifdef __KERNEL__
 
 #include <linux/wait.h>
+#include <linux/spinlock.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
-#include <asm/spinlock.h>
 #include <asm/semaphore.h>
 #include <linux/proc_fs.h>
 #include <linux/config.h>
@@ -491,7 +491,7 @@
 extern void inc_parport_count(void);
 
 /* If PC hardware is the only type supported, we can optimise a bit.  */
-#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#if (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !(defined(CONFIG_PARPORT_AMIGA) || defined(CONFIG_PARPORT_AMIGA_MODULE)) && !(defined(CONFIG_PARPORT_MFC3) || defined(CONFIG_PARPORT_MFC3_MODULE)) && !(defined(CONFIG_PARPORT_ATARI) || defined(CONFIG_PARPORT_ATARI_MODULE)) && !(defined(CONFIG_USB_USS720) || defined(CONFIG_USB_USS720_MODULE)) && !(defined(CONFIG_PARPORT_SUNBPP) || defined(CONFIG_PARPORT_SUNBPP_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
 
 #undef PARPORT_NEED_GENERIC_OPS
 #include <linux/parport_pc.h>
diff -u --recursive --new-file v2.3.17/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.17/linux/include/linux/pci.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/pci.h	Fri Sep 10 11:12:16 1999
@@ -871,6 +871,7 @@
 #define PCI_DEVICE_ID_TTI_HPT366	0x0004
 
 #define PCI_VENDOR_ID_VIA		0x1106
+#define PCI_DEVICE_ID_VIA_8501_0	0x0501
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
 #define PCI_DEVICE_ID_VIA_82C561	0x0561
 #define PCI_DEVICE_ID_VIA_82C586_1	0x0571
@@ -894,6 +895,7 @@
 #define PCI_DEVICE_ID_VIA_82C686_5	0x3058
 #define PCI_DEVICE_ID_VIA_82C686_6	0x3068
 #define PCI_DEVICE_ID_VIA_86C100A	0x6100
+#define PCI_DEVICE_ID_VIA_8501_1	0x8501
 #define PCI_DEVICE_ID_VIA_82C597_1	0x8597
 #define PCI_DEVICE_ID_VIA_82C598_1	0x8598
 
@@ -1532,6 +1534,7 @@
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 int pci_find_capability (struct pci_dev *dev, int cap);
 
+int pci_assign_resource(struct pci_dev *dev, int i);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(u32 min_io, u32 min_mem);
 void pci_set_bus_ranges(void);
diff -u --recursive --new-file v2.3.17/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.17/linux/include/linux/proc_fs.h	Tue Sep  7 12:14:07 1999
+++ linux/include/linux/proc_fs.h	Fri Sep 10 11:12:16 1999
@@ -55,7 +55,8 @@
 	PROC_SOUND,
 	PROC_MTRR, /* whether enabled or not */
 	PROC_FS,
-	PROC_SYSVIPC
+	PROC_SYSVIPC,
+	PROC_DRIVER,
 };
 
 enum pid_directory_inos {
@@ -330,6 +331,7 @@
 extern struct proc_dir_entry proc_mca;
 extern struct proc_dir_entry *proc_bus;
 extern struct proc_dir_entry *proc_sysvipc;
+extern struct proc_dir_entry proc_root_driver;
 
 extern struct inode_operations proc_scsi_inode_operations;
 
@@ -339,6 +341,19 @@
 extern int proc_register(struct proc_dir_entry *, struct proc_dir_entry *);
 extern int proc_unregister(struct proc_dir_entry *, int);
 
+/*
+ * generic.c
+ */
+extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
+					        struct proc_dir_entry *parent);
+extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
+
+
+
+/*
+ * inlined /proc helper functions
+ */
+
 static inline int proc_net_register(struct proc_dir_entry * x)
 {
 	return proc_register(proc_net, x);
@@ -381,6 +396,50 @@
     }
 }
 
+
+/*
+ * retrieve the proc_dir_entry associated with /proc/driver/$module_name
+ */
+extern inline
+struct proc_dir_entry *proc_driver_find (const char *module_name)
+{
+        struct proc_dir_entry *p;
+        
+        p = proc_root_driver.subdir;
+        while (p != NULL) {
+                if (strcmp (p->name, module_name) == 0)
+                        return p;
+                
+                p = p->next;
+        }
+        return NULL;
+}
+
+
+/*
+ * remove /proc/driver/$module_name, and all its contents
+ */
+extern inline int proc_driver_unregister(const char *module_name)
+{
+        remove_proc_entry (module_name, &proc_root_driver);
+        return 0;
+}
+
+
+/*
+ * create driver-specific playground directory, /proc/driver/$module_name
+ */
+extern inline int proc_driver_register(const char *module_name)
+{
+        struct proc_dir_entry *p;
+
+        p = create_proc_entry (module_name, S_IFDIR, &proc_root_driver);
+
+        return (p == NULL) ? -1 : 0;
+}
+
+
+
 extern struct super_block *proc_super_blocks;
 extern struct dentry_operations proc_dentry_operations;
 extern struct super_block *proc_read_super(struct super_block *,void *,int);
@@ -443,13 +502,6 @@
 extern struct inode_operations proc_sysvipc_inode_operations;
 
 /*
- * generic.c
- */
-struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
-					 struct proc_dir_entry *parent);
-void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
-
-/*
  * proc_tty.c
  */
 extern void proc_tty_init(void);
@@ -481,6 +533,23 @@
 extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
 extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
 
+extern inline
+struct proc_dir_entry *proc_driver_find (const char *module_name)
+{
+        return NULL;
+}
+
+extern inline int proc_driver_unregister(const char *module_name)
+{
+        return 0;
+}
+
+extern inline int proc_driver_register(const char *module_name)
+{
+        return 0;
+}
+
+
+#endif /* CONFIG_PROC_FS */
 
-#endif
 #endif /* _LINUX_PROC_FS_H */
diff -u --recursive --new-file v2.3.17/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.17/linux/include/linux/sched.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/sched.h	Thu Sep  9 22:17:31 1999
@@ -126,7 +126,7 @@
 
 #ifdef __KERNEL__
 
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 /*
  * This serializes "schedule()" and also protects
diff -u --recursive --new-file v2.3.17/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.3.17/linux/include/linux/skbuff.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/skbuff.h	Thu Sep  9 22:17:34 1999
@@ -21,7 +21,7 @@
 
 #include <asm/atomic.h>
 #include <asm/types.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #define HAVE_ALLOC_SKB		/* For the drivers to know */
 #define HAVE_ALIGNABLE_SKB	/* Ditto 8)		   */
diff -u --recursive --new-file v2.3.17/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.3.17/linux/include/linux/socket.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/socket.h	Wed Sep  8 11:14:32 1999
@@ -252,6 +252,10 @@
 #define TCP_NODELAY	1
 #define TCP_MAXSEG	2
 #define TCP_CORK	3	/* Linux specific (for use with sendfile) */
+#define TCP_KEEPIDLE	4
+#define TCP_KEEPINTVL	5
+#define TCP_KEEPCNT	6
+#define TCP_SYNCNT	7
 
 #ifdef __KERNEL__
 extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
diff -u --recursive --new-file v2.3.17/linux/include/linux/spinlock.h linux/include/linux/spinlock.h
--- v2.3.17/linux/include/linux/spinlock.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/spinlock.h	Fri Sep 10 12:54:32 1999
@@ -0,0 +1,120 @@
+#ifndef __LINUX_SPINLOCK_H
+#define __LINUX_SPINLOCK_H
+
+/*
+ * These are the generic versions of the spinlocks and read-write
+ * locks..
+ */
+#define spin_lock_irqsave(lock, flags)		do { local_irq_save(flags);       spin_lock(lock); } while (0)
+#define spin_lock_irq(lock)			do { local_irq_disable();         spin_lock(lock); } while (0)
+#define spin_lock_bh(lock)			do { local_bh_disable();          spin_lock(lock); } while (0)
+
+#define read_lock_irqsave(lock, flags)		do { local_irq_save(flags);       read_lock(lock); } while (0)
+#define read_lock_irq(lock)			do { local_irq_disable();         read_lock(lock); } while (0)
+#define read_lock_bh(lock)			do { local_bh_disable();          read_lock(lock); } while (0)
+
+#define write_lock_irqsave(lock, flags)		do { local_irq_save(flags);      write_lock(lock); } while (0)
+#define write_lock_irq(lock)			do { local_irq_disable();        write_lock(lock); } while (0)
+#define write_lock_bh(lock)			do { local_bh_disable();         write_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags)	do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
+#define spin_unlock_irq(lock)			do { spin_unlock(lock);  local_irq_enable();       } while (0)
+#define spin_unlock_bh(lock)			do { spin_unlock(lock);  local_bh_enable();        } while (0)
+
+#define read_unlock_irqrestore(lock, flags)	do { read_unlock(lock);  local_irq_restore(flags); } while (0)
+#define read_unlock_irq(lock)			do { read_unlock(lock);  local_irq_enable();       } while (0)
+#define read_unlock_bh(lock)			do { read_unlock(lock);  local_bh_enable();        } while (0)
+
+#define write_unlock_irqrestore(lock, flags)	do { write_unlock(lock); local_irq_restore(flags); } while (0)
+#define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
+#define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
+
+#ifdef __SMP__
+#include <asm/spinlock.h>
+
+#else /* !SMP */
+
+#define DEBUG_SPINLOCKS	0	/* 0 == no debugging, 1 == maintain lock state, 2 == full debug */
+
+#if (DEBUG_SPINLOCKS < 1)
+
+/*
+ * Your basic spinlocks, allowing only a single CPU anywhere
+ *
+ * Gcc-2.7.x has a nasty bug with empty initializers.
+ */
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } spinlock_t;
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+#endif
+
+#define spin_lock_init(lock)	do { } while(0)
+#define spin_lock(lock)		(void)(lock) /* Not "unused variable". */
+#define spin_trylock(lock)	(1)
+#define spin_unlock_wait(lock)	do { } while(0)
+#define spin_unlock(lock)	do { } while(0)
+
+#elif (DEBUG_SPINLOCKS < 2)
+
+typedef struct {
+	volatile unsigned int lock;
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
+
+#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
+#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
+
+#define spin_lock(x)		do { (x)->lock = 1; } while (0)
+#define spin_unlock_wait(x)	do { } while (0)
+#define spin_unlock(x)		do { (x)->lock = 0; } while (0)
+
+#else /* (DEBUG_SPINLOCKS >= 2) */
+
+typedef struct {
+	volatile unsigned int lock;
+	volatile unsigned int babble;
+	const char *module;
+} spinlock_t;
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ }
+
+#include <linux/kernel.h>
+
+#define spin_lock_init(x)	do { (x)->lock = 0; } while (0)
+#define spin_trylock(lock)	(!test_and_set_bit(0,(lock)))
+
+#define spin_lock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_lock(%s:%p) already locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 1; restore_flags(__spinflags);} while (0)
+#define spin_unlock_wait(x)	do {unsigned long __spinflags; save_flags(__spinflags); cli(); if ((x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock_wait(%s:%p) deadlock\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} restore_flags(__spinflags);} while (0)
+#define spin_unlock(x)		do {unsigned long __spinflags; save_flags(__spinflags); cli(); if (!(x)->lock&&(x)->babble) {printk("%s:%d: spin_unlock(%s:%p) not locked\n", __BASE_FILE__,__LINE__, (x)->module, (x));(x)->babble--;} (x)->lock = 0; restore_flags(__spinflags);} while (0)
+
+#endif	/* DEBUG_SPINLOCKS */
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ *
+ * Gcc-2.7.x has a nasty bug with empty initializers.
+ */
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
+  typedef struct { } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { }
+#else
+  typedef struct { int gcc_is_buggy; } rwlock_t;
+  #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
+
+#define read_lock(lock)		(void)(lock) /* Not "unused variable". */
+#define read_unlock(lock)	do { } while(0)
+#define write_lock(lock)	(void)(lock) /* Not "unused variable". */
+#define write_unlock(lock)	do { } while(0)
+
+#endif /* !SMP */
+#endif /* __LINUX_SPINLOCK_H */
diff -u --recursive --new-file v2.3.17/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.17/linux/include/linux/sysctl.h	Tue Aug 31 17:29:15 1999
+++ linux/include/linux/sysctl.h	Fri Sep 10 11:06:19 1999
@@ -237,7 +237,9 @@
 	NET_IPV4_ICMP_ECHOREPLY_RATE=63,
 	NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
 	NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
-	NET_TCP_TW_RECYCLE=66
+	NET_TCP_TW_RECYCLE=66,
+	NET_IPV4_ALWAYS_DEFRAG=67,
+	NET_IPV4_TCP_KEEPALIVE_INTVL=68,
 };
 
 enum {
diff -u --recursive --new-file v2.3.17/linux/include/linux/tqueue.h linux/include/linux/tqueue.h
--- v2.3.17/linux/include/linux/tqueue.h	Wed Aug 18 16:43:29 1999
+++ linux/include/linux/tqueue.h	Thu Sep  9 22:17:31 1999
@@ -13,9 +13,9 @@
 #ifndef _LINUX_TQUEUE_H
 #define _LINUX_TQUEUE_H
 
+#include <linux/spinlock.h>
 #include <asm/bitops.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 /*
  * New proposed "bottom half" handlers:
diff -u --recursive --new-file v2.3.17/linux/include/linux/wait.h linux/include/linux/wait.h
--- v2.3.17/linux/include/linux/wait.h	Wed Aug 18 16:43:30 1999
+++ linux/include/linux/wait.h	Thu Sep  9 22:17:31 1999
@@ -11,9 +11,9 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/stddef.h>
+#include <linux/spinlock.h>
 
 #include <asm/page.h>
-#include <asm/spinlock.h>
 #include <asm/processor.h>
 
 /*
diff -u --recursive --new-file v2.3.17/linux/include/net/atmclip.h linux/include/net/atmclip.h
--- v2.3.17/linux/include/net/atmclip.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/atmclip.h	Thu Sep  9 22:22:06 1999
@@ -46,7 +46,7 @@
 struct clip_priv {
 	char name[8];			/* interface name */
 	int number;			/* for convenience ... */
-	struct enet_statistics stats;
+	struct net_device_stats stats;
 	struct net_device *next;		/* next CLIP interface */
 };
 
@@ -58,5 +58,6 @@
 int clip_mkip(struct atm_vcc *vcc,int timeout);
 int clip_setentry(struct atm_vcc *vcc,u32 ip);
 int clip_encap(struct atm_vcc *vcc,int mode);
+void atm_clip_init(void);
 
 #endif
diff -u --recursive --new-file v2.3.17/linux/include/net/irda/irda_device.h linux/include/net/irda/irda_device.h
--- v2.3.17/linux/include/net/irda/irda_device.h	Tue Aug 31 17:29:15 1999
+++ linux/include/net/irda/irda_device.h	Wed Sep  8 11:59:48 1999
@@ -35,8 +35,7 @@
 
 #include <linux/tty.h>
 #include <linux/netdevice.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/qos.h>
diff -u --recursive --new-file v2.3.17/linux/include/net/irda/irqueue.h linux/include/net/irda/irqueue.h
--- v2.3.17/linux/include/net/irda/irqueue.h	Tue Aug 31 17:29:15 1999
+++ linux/include/net/irda/irqueue.h	Thu Sep  9 22:19:23 1999
@@ -28,7 +28,7 @@
  ********************************************************************/
 
 #include <linux/types.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #ifndef QUEUE_H
 #define QUEUE_H
diff -u --recursive --new-file v2.3.17/linux/include/net/irda/irttp.h linux/include/net/irda/irttp.h
--- v2.3.17/linux/include/net/irda/irttp.h	Tue Aug 31 17:29:15 1999
+++ linux/include/net/irda/irttp.h	Wed Sep  8 11:59:48 1999
@@ -28,7 +28,7 @@
 
 #include <linux/types.h>
 #include <linux/skbuff.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irlmp.h>
diff -u --recursive --new-file v2.3.17/linux/include/net/sock.h linux/include/net/sock.h
--- v2.3.17/linux/include/net/sock.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/sock.h	Thu Sep  9 22:19:23 1999
@@ -317,6 +317,11 @@
 
 	int syn_backlog;	/* Backlog of received SYNs */
 	int write_pending;
+	
+	unsigned int		keepalive_time;	  /* time before keep alive takes place */
+	unsigned int		keepalive_intvl;  /* time interval between keep alive probes */
+	unsigned char  		keepalive_probes; /* num of allowed keep alive probes */
+	unsigned char		syn_retries;	  /* num of allowed syn retries */
 };
 
  	
diff -u --recursive --new-file v2.3.17/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.3.17/linux/include/net/tcp.h	Thu Aug 26 13:05:41 1999
+++ linux/include/net/tcp.h	Thu Sep  9 22:21:27 1999
@@ -33,7 +33,7 @@
 struct tcp_ehash_bucket {
 	rwlock_t	lock;
 	struct sock	*chain;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+} __attribute__((__aligned__(8)));
 
 extern int tcp_ehash_size;
 extern struct tcp_ehash_bucket *tcp_ehash;
@@ -286,7 +286,12 @@
 				 * there is no window			*/
 #define TCP_KEEPALIVE_TIME (120*60*HZ)		/* two hours */
 #define TCP_KEEPALIVE_PROBES	9		/* Max of 9 keepalive probes	*/
-#define TCP_KEEPALIVE_PERIOD ((75*HZ)>>2)	/* period of keepalive check	*/
+#define TCP_KEEPALIVE_INTVL	(75*HZ)
+
+#define MAX_TCP_KEEPIDLE	32767
+#define MAX_TCP_KEEPINTVL	32767
+#define MAX_TCP_KEEPCNT		127
+#define MAX_TCP_SYNCNT		127
 
 #define TCP_SYNACK_PERIOD	(HZ/2) /* How often to run the synack slow timer */
 #define TCP_QUICK_TRIES		8  /* How often we try to retransmit, until
@@ -332,6 +337,12 @@
 #define TIME_PROBE0	4
 #define TIME_KEEPOPEN	5
 
+/* sysctl variables for tcp */
+extern int sysctl_tcp_keepalive_time;
+extern int sysctl_tcp_keepalive_probes;
+extern int sysctl_tcp_keepalive_intvl;
+extern int sysctl_tcp_syn_retries;
+
 struct open_request;
 
 struct or_calltable {
@@ -611,7 +622,7 @@
 extern void tcp_send_partial(struct sock *);
 extern void tcp_write_wakeup(struct sock *);
 extern void tcp_send_fin(struct sock *sk);
-extern void tcp_send_active_reset(struct sock *sk);
+extern void tcp_send_active_reset(struct sock *sk, int priority);
 extern int  tcp_send_synack(struct sock *);
 extern void tcp_transmit_skb(struct sock *, struct sk_buff *);
 extern void tcp_send_skb(struct sock *, struct sk_buff *, int force_queue);
@@ -1229,6 +1240,22 @@
 {
 	if (atomic_dec_and_test(&tcp_lhash_users))
 		wake_up(&tcp_lhash_wait);
+}
+
+static inline int keepalive_intvl_when(struct tcp_opt *tp)
+{
+	if (tp->keepalive_intvl)
+		return tp->keepalive_intvl;
+	else
+		return sysctl_tcp_keepalive_intvl;
+}
+
+static inline int keepalive_time_when(struct tcp_opt *tp)
+{
+	if (tp->keepalive_time)
+		return tp->keepalive_time;
+	else
+		return sysctl_tcp_keepalive_time;
 }
 
 #endif	/* _TCP_H */
diff -u --recursive --new-file v2.3.17/linux/kernel/dma.c linux/kernel/dma.c
--- v2.3.17/linux/kernel/dma.c	Mon Oct 12 11:50:15 1998
+++ linux/kernel/dma.c	Wed Sep  8 11:42:15 1999
@@ -12,9 +12,9 @@
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/spinlock.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/spinlock.h>
 
 
 /* A note on resource allocation:
diff -u --recursive --new-file v2.3.17/linux/kernel/printk.c linux/kernel/printk.c
--- v2.3.17/linux/kernel/printk.c	Thu Aug 26 13:05:42 1999
+++ linux/kernel/printk.c	Fri Sep 10 13:15:51 1999
@@ -174,10 +174,10 @@
 		error = verify_area(VERIFY_WRITE,buf,len);
 		if (error)
 			goto out;
-		spin_lock_irq(&console_lock);
 		count = len;
 		if (count > LOG_BUF_LEN)
 			count = LOG_BUF_LEN;
+		spin_lock_irq(&console_lock);
 		if (count > logged_chars)
 			count = logged_chars;
 		if (do_clear)
diff -u --recursive --new-file v2.3.17/linux/kernel/resource.c linux/kernel/resource.c
--- v2.3.17/linux/kernel/resource.c	Tue Aug 31 17:29:15 1999
+++ linux/kernel/resource.c	Wed Sep  8 11:42:15 1999
@@ -12,8 +12,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
-
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF, IORESOURCE_IO };
 struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF, IORESOURCE_MEM };
diff -u --recursive --new-file v2.3.17/linux/net/Config.in linux/net/Config.in
--- v2.3.17/linux/net/Config.in	Tue Aug 31 17:29:15 1999
+++ linux/net/Config.in	Wed Sep  8 11:14:32 1999
@@ -41,7 +41,6 @@
       if [ "$CONFIG_ATM_CLIP" = "y" ]; then
 	bool '    Do NOT send ICMP if no neighbour' CONFIG_ATM_CLIP_NO_ICMP n
       fi
-#      bool '  Application REQUested IP over ATM' CONFIG_AREQUIPA y
     fi
     tristate '  LAN Emulation (LANE) support' CONFIG_ATM_LANE y
     if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then
diff -u --recursive --new-file v2.3.17/linux/net/atm/Makefile linux/net/atm/Makefile
--- v2.3.17/linux/net/atm/Makefile	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/Makefile	Wed Sep  8 11:14:32 1999
@@ -13,8 +13,8 @@
 
 ifeq ($(CONFIG_ATM),y)
 
-O_OBJS	= addr.o pvc.o raw.o signaling.o svc.o # party.o
-OX_OBJS = common.o atm_misc.o resources.o
+O_OBJS	= addr.o pvc.o signaling.o svc.o
+OX_OBJS = common.o atm_misc.o raw.o resources.o
 
 ifeq ($(CONFIG_MMU_HACKS),y)
 O_OBJS += mmuio.o
@@ -22,11 +22,6 @@
 
 ifeq ($(CONFIG_ATM_CLIP),y)
 O_OBJS += clip.o
-NEED_IPCOM = ipcommon.o
-endif
-
-ifeq ($(CONFIG_AREQUIPA),y)
-O_OBJS += arequipa.o
 NEED_IPCOM = ipcommon.o
 endif
 
diff -u --recursive --new-file v2.3.17/linux/net/atm/addr.c linux/net/atm/addr.c
--- v2.3.17/linux/net/atm/addr.c	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/addr.c	Wed Sep  8 11:14:32 1999
@@ -18,8 +18,7 @@
 
 	if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
 	if (!*addr->sas_addr.pub)
-		if (!*addr->sas_addr.prv) return -EINVAL;
-		else return 0;
+		return *addr->sas_addr.prv ? 0 : -EINVAL;
 	for (i = 1; i < ATM_E164_LEN+1; i++) /* make sure it's \0-terminated */
 		if (!addr->sas_addr.pub[i]) return 0;
 	return -EINVAL;
diff -u --recursive --new-file v2.3.17/linux/net/atm/atm_misc.c linux/net/atm/atm_misc.c
--- v2.3.17/linux/net/atm/atm_misc.c	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/atm_misc.c	Wed Sep  8 11:14:32 1999
@@ -23,6 +23,26 @@
 }
 
 
+struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
+    int gfp_flags)
+{
+	int guess = atm_guess_pdu2truesize(pdu_size);
+
+	atm_force_charge(vcc,guess);
+	if (atomic_read(&vcc->rx_inuse) <= vcc->rx_quota) {
+		struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
+
+		if (skb) {
+			atomic_add(skb->truesize-guess,&vcc->rx_inuse);
+			return skb;
+		}
+	}
+	atm_return(vcc,guess);
+	vcc->stats->rx_drop++;
+	return NULL;
+}
+
+
 static int check_ci(struct atm_vcc *vcc,short vpi,int vci)
 {
 	struct atm_vcc *walk;
@@ -118,6 +138,6 @@
 
 
 EXPORT_SYMBOL(atm_charge);
-EXPORT_SYMBOL(atm_return);
+EXPORT_SYMBOL(atm_alloc_charge);
 EXPORT_SYMBOL(atm_find_ci);
 EXPORT_SYMBOL(atm_pcr_goal);
diff -u --recursive --new-file v2.3.17/linux/net/atm/clip.c linux/net/atm/clip.c
--- v2.3.17/linux/net/atm/clip.c	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/clip.c	Wed Sep  8 11:14:32 1999
@@ -45,7 +45,7 @@
 
 struct net_device *clip_devs = NULL;
 struct atm_vcc *atmarpd = NULL;
-static struct timer_list idle_timer = { NULL, NULL, 0L, 0L, NULL };
+static struct timer_list idle_timer;
 static int start_timer = 1;
 
 
@@ -207,12 +207,14 @@
 		skb_pull(skb,RFC1483LLC_LEN);
 		if (skb->protocol == htons(ETH_P_ARP)) {
 			PRIV(skb->dev)->stats.rx_packets++;
+			PRIV(skb->dev)->stats.rx_bytes += skb->len;
 			clip_arp_rcv(skb);
 			return;
 		}
 	}
 	clip_vcc->last_use = jiffies;
 	PRIV(skb->dev)->stats.rx_packets++;
+	PRIV(skb->dev)->stats.rx_bytes += skb->len;
 	netif_rx(skb);
 }
 
@@ -395,13 +397,14 @@
 	entry->vccs->last_use = jiffies;
 	DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,ATM_SKB(skb)->vcc,
 	    ATM_SKB(skb)->vcc->dev);
-	(void) ATM_SKB(skb)->vcc->dev->ops->send(ATM_SKB(skb)->vcc,skb);
 	PRIV(dev)->stats.tx_packets++;
+	PRIV(dev)->stats.tx_bytes += skb->len;
+	(void) ATM_SKB(skb)->vcc->dev->ops->send(ATM_SKB(skb)->vcc,skb);
 	return 0;
 }
 
 
-static struct enet_statistics *clip_get_stats(struct net_device *dev)
+static struct net_device_stats *clip_get_stats(struct net_device *dev)
 {
 	return &PRIV(dev)->stats;
 }
@@ -437,8 +440,11 @@
 			kfree_skb(skb);
 		}
 		else {
+			unsigned int len = skb->len;
+
 			clip_push(vcc,skb);
 			PRIV(skb->dev)->stats.rx_packets--;
+			PRIV(skb->dev)->stats.rx_bytes -= len;
 		}
 	return 0;
 }
@@ -672,6 +678,7 @@
 	if (atmarpd) return -EADDRINUSE;
 	if (start_timer) {
 		start_timer = 0;
+		init_timer(&idle_timer);
 		idle_timer.expires = jiffies+CLIP_CHECK_INTERVAL*HZ;
 		idle_timer.function = idle_timer_check;
 		add_timer(&idle_timer);
@@ -691,4 +698,12 @@
 		if (dev->flags & IFF_UP)
 			(void) to_atmarpd(act_up,PRIV(dev)->number,0);
 	return 0;
+}
+
+
+void atm_clip_init(void)
+{
+	clip_tbl.lock = RW_LOCK_UNLOCKED;
+	clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id,
+	    clip_tbl.entry_size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
 }
diff -u --recursive --new-file v2.3.17/linux/net/atm/common.c linux/net/atm/common.c
--- v2.3.17/linux/net/atm/common.c	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/common.c	Wed Sep  8 11:14:32 1999
@@ -29,10 +29,6 @@
 #include <linux/uio.h>
 #endif
 
-#ifdef CONFIG_AREQUIPA
-#include <linux/arequipa.h>
-#endif
-
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 #include <linux/atmlec.h>
 #include "lec.h"
@@ -107,10 +103,6 @@
 	if (sock->type == SOCK_STREAM) return -EINVAL;
 	if (!(sk = alloc_atm_vcc_sk(family))) return -ENOMEM;
 	vcc = sk->protinfo.af_atm;
-#ifdef CONFIG_AREQUIPA
-	vcc->upper = NULL;
-	vcc->sock = sock;
-#endif
 	vcc->flags = ATM_VF_SCRX | ATM_VF_SCTX;
 	vcc->dev = NULL;
 	vcc->family = sock->ops->family;
@@ -620,29 +612,6 @@
 			if (!capable(CAP_NET_ADMIN)) return -EPERM;
 			return clip_encap(vcc,arg);
 #endif
-#ifdef CONFIG_AREQUIPA
-		case AREQUIPA_PRESET:
-			{
-				struct socket *upper;
-
-				if (!(upper = sockfd_lookup(arg,&error)))
-					return error;
-				if (upper->ops->family != PF_INET)
-					return -EPROTOTYPE;
-				return arequipa_preset(sock,upper->sk);
-			}
-		case AREQUIPA_INCOMING:
-			return arequipa_incoming(sock);
-		case AREQUIPA_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			error = arequipad_attach(vcc);
-			if (!error) sock->state = SS_CONNECTED;
-			return error;
-		case AREQUIPA_WORK:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			arequipa_work();
-			return 0;
-#endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
                 case ATMLEC_CTRL:
                         if (!capable(CAP_NET_ADMIN)) return -EPERM;
@@ -899,6 +868,8 @@
 		case SO_BCTXOPT:
 			/* fall through */
 		case SO_BCRXOPT:
+			printk(KERN_WARNING "Warning: SO_BCTXOPT/SO_BCRXOPT "
+			   "are obsolete\n");
 			break;
 		case SO_ATMQOS:
 			if (!(vcc->flags & ATM_VF_HASQOS)) return -EINVAL;
@@ -907,6 +878,19 @@
 		case SO_SETCLP:
 			return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 :
 			  0,(unsigned long *) optval) ? -EFAULT : 0;
+		case SO_ATMPVC:
+			{
+				struct sockaddr_atmpvc pvc;
+
+				if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR))
+					return -ENOTCONN;
+				pvc.sap_family = AF_ATMPVC;
+				pvc.sap_addr.itf = vcc->dev->number;
+				pvc.sap_addr.vpi = vcc->vpi;
+				pvc.sap_addr.vci = vcc->vci;
+				return copy_to_user(optval,&pvc,sizeof(pvc)) ?
+				    -EFAULT : 0;
+			}
 		default:
 			if (level == SOL_SOCKET) return -EINVAL;
 			break;
@@ -919,7 +903,7 @@
 int atm_setsockopt(struct socket *sock,int level,int optname,char *optval,
     int optlen)
 {
-	if (level == __SO_LEVEL(optname) && optlen != __SO_SIZE(optname))
+	if (__SO_LEVEL_MATCH(optname, level) && optlen != __SO_SIZE(optname))
 		return -EINVAL;
 	return atm_do_setsockopt(sock,level,optname,optval,optlen);
 }
@@ -931,7 +915,7 @@
 	int len;
 
 	if (get_user(len,optlen)) return -EFAULT;
-	if (level == __SO_LEVEL(optname) && len != __SO_SIZE(optname))
+	if (__SO_LEVEL_MATCH(optname, level) && len != __SO_SIZE(optname))
 		return -EINVAL;
 	return atm_do_getsockopt(sock,level,optname,optval,len);
 }
diff -u --recursive --new-file v2.3.17/linux/net/atm/lec.c linux/net/atm/lec.c
--- v2.3.17/linux/net/atm/lec.c	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/lec.c	Wed Sep  8 11:14:32 1999
@@ -59,7 +59,7 @@
 static int lec_open(struct net_device *dev);
 static int lec_send_packet(struct sk_buff *skb, struct net_device *dev);
 static int lec_close(struct net_device *dev);
-static struct enet_statistics *lec_get_stats(struct net_device *dev);
+static struct net_device_stats *lec_get_stats(struct net_device *dev);
 static int lec_init(struct net_device *dev);
 static __inline__ struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
                                                      unsigned char *mac_addr);
@@ -165,8 +165,10 @@
         /* offset 4 comes from LAN destination field in LE control frames */
         if (trh->rcf & htons((uint16_t)TR_RCF_DIR_BIT))
                 memcpy(&rdesc[4], &trh->rseg[num_rdsc-2], sizeof(uint16_t));
-        else
+        else {
                 memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
+                rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
+        }
 
         return NULL;
 }
@@ -189,7 +191,7 @@
         dev->tbusy = 0;
         dev->start = 1;
         dev->interrupt = 1;
-        memset(&priv->stats,0,sizeof(struct enet_statistics));
+        memset(&priv->stats,0,sizeof(struct net_device_stats));
         
         return 0;
 }
@@ -348,16 +350,18 @@
                         ATM_SKB(skb2)->atm_options = send_vcc->atm_options;
                         DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name,
                                send_vcc->vpi, send_vcc->vci);       
-                        send_vcc->dev->ops->send(send_vcc, skb2);
                         priv->stats.tx_packets++;
+                        priv->stats.tx_bytes += skb2->len;
+                        send_vcc->dev->ops->send(send_vcc, skb2);
                 }
 
                 ATM_SKB(skb)->vcc = send_vcc;
                 atomic_add(skb->truesize, &send_vcc->tx_inuse);
                 ATM_SKB(skb)->iovcnt = 0;
                 ATM_SKB(skb)->atm_options = send_vcc->atm_options;
-                send_vcc->dev->ops->send(send_vcc, skb);
                 priv->stats.tx_packets++;
+                priv->stats.tx_bytes += skb->len;
+                send_vcc->dev->ops->send(send_vcc, skb);
         }
         /* Should we wait for card's device driver to notify us? */
         dev->tbusy=0;
@@ -378,12 +382,10 @@
  * Get the current statistics.
  * This may be called with the card open or closed.
  */
-static struct enet_statistics *
+static struct net_device_stats *
 lec_get_stats(struct net_device *dev)
 {
-        struct lec_priv *priv = (struct lec_priv *)dev->priv;
-        
-        return (struct enet_statistics *)&priv->stats;
+        return &((struct lec_priv *)dev->priv)->stats;
 }
 
 static int 
@@ -714,8 +716,9 @@
                 else
 #endif
                 skb->protocol = eth_type_trans(skb, dev);
-                netif_rx(skb);
                 priv->stats.rx_packets++;
+                priv->stats.rx_bytes += skb->len;
+                netif_rx(skb);
         }
 }
 
@@ -769,12 +772,12 @@
                 return -EINVAL;
 #endif
         if (!dev_lec[i]) {
-                dev_lec[i] = (struct net_device*)kmalloc(sizeof(struct net_device)+
-                                                     sizeof(myname)+1, 
-                                                     GFP_KERNEL);
+                dev_lec[i] = (struct net_device*)
+		    kmalloc(sizeof(struct net_device)+sizeof(myname)+1, 
+		    GFP_KERNEL);
                 if (!dev_lec[i])
                         return -ENOMEM;
-                memset(dev_lec[i],0, sizeof(struct net_device)+sizeof(myname)+1);
+                memset(dev_lec[i],0,sizeof(struct net_device)+sizeof(myname)+1);
 
                 dev_lec[i]->priv = kmalloc(sizeof(struct lec_priv), GFP_KERNEL);
                 if (!dev_lec[i]->priv)
@@ -888,7 +891,8 @@
  * lec will be used.
  * If dst_mac == NULL, targetless LE_ARP will be sent
  */
-static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs)
+static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
+    u8 **tlvs, u32 *sizeoftlvs)
 {
         struct lec_priv *priv = (struct lec_priv *)dev->priv;
         struct lec_arp_table *table;
@@ -968,7 +972,8 @@
  * LANE2: 3.1.5, LE_ASSOCIATE.indication
  *
  */
-static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr, u8 *tlvs, u32 sizeoftlvs)
+static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
+    u8 *tlvs, u32 sizeoftlvs)
 {
 #if 0
         int i = 0;
@@ -1004,8 +1009,6 @@
                 priv->lane2_ops->associate_indicator(dev, mac_addr,
                                                      tlvs, sizeoftlvs);
         }
-        else
-                printk("lane:(%s) lane2_associate_ind: could not notify MPOA\n", dev->name);
         return;
 }
 
diff -u --recursive --new-file v2.3.17/linux/net/atm/lec.h linux/net/atm/lec.h
--- v2.3.17/linux/net/atm/lec.h	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/lec.h	Wed Sep  8 11:14:32 1999
@@ -74,7 +74,7 @@
 #define LEC_ARP_TABLE_SIZE 16
 
 struct lec_priv {
-        struct enet_statistics stats;
+        struct net_device_stats stats;
         unsigned short lecid;      /* Lecid of this client */
         struct lec_arp_table *lec_arp_empty_ones;
         /* Used for storing VCC's that don't have a MAC address attached yet */
diff -u --recursive --new-file v2.3.17/linux/net/atm/mpc.h linux/net/atm/mpc.h
--- v2.3.17/linux/net/atm/mpc.h	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/mpc.h	Wed Sep  8 11:54:14 1999
@@ -4,7 +4,7 @@
 #include <linux/atm.h>
 #include <linux/atmmpc.h>
 #include <linux/skbuff.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include "mpoa_caches.h"
 
 /* kernel -> mpc-daemon */
@@ -16,7 +16,7 @@
 
 struct mpoa_client {
         struct mpoa_client *next;
-        struct net_device *dev;          /* lec in question                     */
+        struct net_device *dev;      /* lec in question                     */
         int dev_num;                 /* e.g. 2 for lec2                     */
         int (*old_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev);
         struct atm_vcc *mpoad_vcc;   /* control channel to mpoad            */
diff -u --recursive --new-file v2.3.17/linux/net/atm/proc.c linux/net/atm/proc.c
--- v2.3.17/linux/net/atm/proc.c	Tue Aug 31 17:29:15 1999
+++ linux/net/atm/proc.c	Wed Sep  8 11:14:32 1999
@@ -38,11 +38,6 @@
 #include "common.h" /* atm_proc_init prototype */
 #include "signaling.h" /* to get sigd - ugly too */
 
-#ifdef CONFIG_AREQUIPA
-#include <linux/arequipa.h>
-void atm_push_arequipa(struct atm_vcc *vcc,struct sk_buff *skb);
-#endif
-
 #ifdef CONFIG_ATM_CLIP
 #include <net/atmclip.h>
 #include "ipcommon.h"
@@ -111,9 +106,6 @@
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 ENTRY(lec);
 #endif
-#ifdef CONFIG_AREQUIPA
-ENTRY(arequipa);
-#endif
 
 
 static int atm_header(ino_t ino,char *buf)
@@ -137,10 +129,6 @@
 		    "                          Status            Flags "
 		    "VPI/VCI Recv VPI/VCI\n");
 #endif
-#ifdef CONFIG_AREQUIPA
-	if (ino == INO(arequipa))
-		return sprintf(buf,"Itf VPI VCI   State    Sock# Inode\n");
-#endif
 	return -EINVAL;
 }
 
@@ -300,37 +288,6 @@
 }
 
 
-#ifdef CONFIG_AREQUIPA
-
-
-static const char *arequipa_state(const struct atm_vcc *vcc)
-{
-	if (!(vcc->flags & ATM_VF_REGIS) && vcc->family != PF_ATMPVC)
-		return "DOOMED";
-	if (vcc->upper) return "ATTACHED";
-	return "DANGLING";
-}
-
-
-static void arequipa_info(struct atm_vcc *vcc,char *buf)
-{
-	char *here;
- 
-	if (!vcc->dev) sprintf(buf,"Unassigned    ");
-	else sprintf(buf,"%3d %3d %5d ",vcc->dev->number,vcc->vpi,vcc->vci);
-        here = strchr(buf,0);
-        here += sprintf(here,"%-8s ",arequipa_state(vcc));
-	if (vcc->upper)
-		here += sprintf(here,"%5d %ld",vcc->upper->num,
-		    vcc->upper->socket && SOCK_INODE(vcc->upper->socket) ?
-		    SOCK_INODE(vcc->upper->socket)->i_ino : 0);
-	strcat(here,"\n");
-}
-
-
-#endif
-
-
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 
 static char*
@@ -458,18 +415,6 @@
 		return 0;
 	}
 #endif
-#ifdef CONFIG_AREQUIPA
-	if (ino == INO(arequipa)) {
-		left = *pos-1;
-		for (dev = atm_devs; dev; dev = dev->next)
-			for (vcc = dev->vccs; vcc; vcc = vcc->next)
-				if (vcc->push == atm_push_arequipa && !left--) {
-					arequipa_info(vcc,buf);
-					return strlen(buf);
-				}
-		return 0;
-	}
-#endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	if (ino == INO(lec)) {
 		struct lec_priv *priv;
@@ -609,9 +554,6 @@
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 	REG(lec);
-#endif
-#ifdef CONFIG_AREQUIPA
-	REG(arequipa);
 #endif
 	return error;
 }
diff -u --recursive --new-file v2.3.17/linux/net/atm/pvc.c linux/net/atm/pvc.c
--- v2.3.17/linux/net/atm/pvc.c	Tue Sep  7 12:14:07 1999
+++ linux/net/atm/pvc.c	Wed Sep  8 11:14:32 1999
@@ -1,6 +1,6 @@
 /* net/atm/pvc.c - ATM PVC sockets */
 
-/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
 
 
 #include <linux/config.h>
@@ -14,9 +14,6 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>		/* for sock_no_* */
-#ifdef CONFIG_AREQUIPA
-#include <linux/arequipa.h>
-#endif
 #ifdef CONFIG_ATM_CLIP
 #include <net/atmclip.h>
 #endif
@@ -66,14 +63,11 @@
     int *sockaddr_len,int peer)
 {
 	struct sockaddr_atmpvc *addr;
-	struct atm_vcc *vcc;
+	struct atm_vcc *vcc = ATM_SD(sock);
 
-#if 0 /* add some sanity checks later ... @@@ */
-	if (sock->state != SS_CONNECTED) return -EINVAL;
-#endif
+	if (!vcc->dev || !(vcc->flags & ATM_VF_ADDR)) return -ENOTCONN;
         *sockaddr_len = sizeof(struct sockaddr_atmpvc);
 	addr = (struct sockaddr_atmpvc *) sockaddr;
-	vcc = ATM_SD(sock);
 	addr->sap_family = AF_ATMPVC;
 	addr->sap_addr.itf = vcc->dev->number;
 	addr->sap_addr.vpi = vcc->vpi;
@@ -102,6 +96,7 @@
 	sock_no_mmap
 };
 
+
 #include <linux/smp_lock.h>
 SOCKOPS_WRAP(pvc_proto, PF_ATMPVC);
 
@@ -137,15 +132,7 @@
 		return;
 	}
 #ifdef CONFIG_ATM_CLIP
-	clip_tbl.lock = RW_LOCK_UNLOCKED;
-	if (clip_tbl.kmem_cachep == NULL)
-		clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id,
-							 clip_tbl.entry_size,
-							 0, SLAB_HWCACHE_ALIGN,
-							 NULL, NULL);
-#endif
-#ifdef CONFIG_AREQUIPA
-	(void) atm_init_arequipa();
+	atm_clip_init();
 #endif
 #ifdef CONFIG_PROC_FS
 	error = atm_proc_init();
diff -u --recursive --new-file v2.3.17/linux/net/atm/raw.c linux/net/atm/raw.c
--- v2.3.17/linux/net/atm/raw.c	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/raw.c	Wed Sep  8 11:14:32 1999
@@ -1,9 +1,10 @@
 /* net/atm/raw.c - Raw AAL0 and AAL5 transports */
 
-/* Written 1995-1998 by Werner Almesberger, EPFL LRC */
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
 
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/atmdev.h>
 #include <linux/kernel.h>
@@ -78,3 +79,6 @@
 	vcc->push_oam = NULL;
 	return 0;
 }
+
+
+EXPORT_SYMBOL(atm_init_aal5);
diff -u --recursive --new-file v2.3.17/linux/net/atm/svc.c linux/net/atm/svc.c
--- v2.3.17/linux/net/atm/svc.c	Tue Aug 31 17:29:15 1999
+++ linux/net/atm/svc.c	Wed Sep  8 11:14:32 1999
@@ -311,7 +311,7 @@
 {
 	struct atm_vcc *vcc;
 
-	if (level != __SO_LEVEL(optname) || optname != SO_ATMSAP ||
+	if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP ||
 	    optlen != sizeof(struct atm_sap))
 		return atm_setsockopt(sock,level,optname,optval,optlen);
 	vcc = ATM_SD(sock);
@@ -326,7 +326,7 @@
 {
 	int len;
 
-	if (level != __SO_LEVEL(optname) || optname != SO_ATMSAP)
+	if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP)
 		return atm_getsockopt(sock,level,optname,optval,optlen);
 	if (get_user(len,optlen)) return -EFAULT;
 	if (len != sizeof(struct atm_sap)) return -EINVAL;
diff -u --recursive --new-file v2.3.17/linux/net/atm/tunable.h linux/net/atm/tunable.h
--- v2.3.17/linux/net/atm/tunable.h	Thu Aug 26 13:05:42 1999
+++ linux/net/atm/tunable.h	Wed Sep  8 11:14:32 1999
@@ -6,13 +6,6 @@
 #ifndef NET_ATM_TUNABLE_H
 #define NET_ATM_TUNABLE_H
 
-#if 0
-/* this is just a reminder - TTS is a device-specific parameter and shall be
-   used inside device drivers only */
-#define ATM_TTS		1000	/* worst-case time to service of device
-				   drivers, in microseconds */
-#endif
-
 #define ATM_RXBQ_DEF	(  64*1024)  /* default RX buffer quota, in bytes */
 #define ATM_TXBQ_DEF	(  64*1024)  /* default TX buffer quota, in bytes */
 #define ATM_RXBQ_MIN	(   1*1024)  /* RX buffer minimum, in bytes */
diff -u --recursive --new-file v2.3.17/linux/net/core/netfilter.c linux/net/core/netfilter.c
--- v2.3.17/linux/net/core/netfilter.c	Tue Aug 31 17:29:15 1999
+++ linux/net/core/netfilter.c	Wed Sep  8 11:51:22 1999
@@ -16,7 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/if.h>
 #include <linux/netdevice.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
@@ -47,6 +47,7 @@
 };
 
 static rwlock_t nf_lock = RW_LOCK_UNLOCKED;
+static DECLARE_MUTEX(nf_sockopt_mutex);
 
 struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
 static LIST_HEAD(nf_sockopts);
@@ -91,15 +92,15 @@
 	write_unlock_bh(&nf_lock);
 }
 
-/* Do inclusive ranges overlap? */
+/* Do exclusive ranges overlap? */
 static inline int overlap(int min1, int max1, int min2, int max2)
 {
-	return (min1 >= min2 && min1 <= max2)
-		|| (max1 >= min2 && max1 <= max2);
+	return (min1 >= min2 && min1 < max2)
+		|| (max1 > min2 && max1 <= max2);
 }
 
-/* Functions to register setsockopt ranges (inclusive). */
-int nf_register_sockopt(struct nf_setsockopt_ops *reg)
+/* Functions to register sockopt ranges (exclusive). */
+int nf_register_sockopt(struct nf_sockopt_ops *reg)
 {
 	struct list_head *i;
 	int ret = 0;
@@ -109,33 +110,44 @@
 		NFDEBUG("nf_register_sockopt: bad val: pf=%i.\n", reg->pf);
 		return -EINVAL;
 	}
-	if (reg->optmin > reg->optmax) {
-		NFDEBUG("nf_register_sockopt: bad val: min=%i max=%i.\n", 
-			reg->optmin, reg->optmax);
+	if (reg->set_optmin > reg->set_optmax) {
+		NFDEBUG("nf_register_sockopt: bad set val: min=%i max=%i.\n", 
+			reg->set_optmin, reg->set_optmax);
+		return -EINVAL;
+	}
+	if (reg->get_optmin > reg->get_optmax) {
+		NFDEBUG("nf_register_sockopt: bad get val: min=%i max=%i.\n", 
+			reg->get_optmin, reg->get_optmax);
 		return -EINVAL;
 	}
 #endif
-	write_lock_bh(&nf_lock);
+	if (down_interruptible(&nf_sockopt_mutex) != 0)
+		return -EINTR;
+
 	for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) {
-		struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i;
+		struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
 		if (ops->pf == reg->pf
-		    && overlap(ops->optmin, ops->optmax, 
-			       reg->optmin, reg->optmax)) {
-			NFDEBUG("nf_register_sockopt overlap: %u-%u v %u-%u\n",
-				ops->optmin, ops->optmax, 
-				reg->optmin, reg->optmax);
+		    && (overlap(ops->set_optmin, ops->set_optmax, 
+				reg->set_optmin, reg->set_optmax)
+			|| overlap(ops->get_optmin, ops->get_optmax, 
+				   reg->get_optmin, reg->get_optmax))) {
+			NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
+				ops->set_optmin, ops->set_optmax, 
+				ops->get_optmin, ops->get_optmax, 
+				reg->set_optmin, reg->set_optmax,
+				reg->get_optmin, reg->get_optmax);
 			ret = -EBUSY;
 			goto out;
 		}
 	}
-	
+
 	list_add(&reg->list, &nf_sockopts);
 out:
-	write_unlock_bh(&nf_lock);
+	up(&nf_sockopt_mutex);
 	return ret;
 }
 
-void nf_unregister_sockopt(struct nf_setsockopt_ops *reg)
+void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
 {
 #ifdef CONFIG_NETFILTER_DEBUG
 	if (reg->pf<0 || reg->pf>=NPROTO) {
@@ -143,9 +155,10 @@
 		return;
 	}
 #endif
-	write_lock_bh(&nf_lock);
+	/* No point being interruptible: we're probably in cleanup_module() */
+	down(&nf_sockopt_mutex);
 	list_del(&reg->list);
-	write_unlock_bh(&nf_lock);
+	up(&nf_sockopt_mutex);
 }
 
 #ifdef CONFIG_NETFILTER_DEBUG
@@ -290,8 +303,9 @@
 	read_unlock_bh(&nf_lock);
 }
 
-/* Call setsockopt() */
-int nf_setsockopt(int pf, int val, char *opt, unsigned int len)
+/* Call get/setsockopt() */
+static int nf_sockopt(struct sock *sk, int pf, int val, 
+		      char *opt, int *len, int get)
 {
 	struct list_head *i;
 	int ret;
@@ -299,19 +313,42 @@
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
 
-	read_lock_bh(&nf_lock);
+	if (down_interruptible(&nf_sockopt_mutex) != 0)
+		return -EINTR;
+
 	for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) {
-		struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i;
-		if (ops->pf == pf 
-		    && val >= ops->optmin && val <= ops->optmax) {
-			ret = ops->fn(val, opt, len);
-			goto out;
+		struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
+		if (ops->pf == pf) {
+			if (get) {
+				if (val >= ops->get_optmin
+				    && val < ops->get_optmax) {
+					ret = ops->get(sk, val, opt, len);
+					goto out;
+				}
+			} else {
+				if (val >= ops->set_optmin
+				    && val < ops->set_optmax) {
+					ret = ops->set(sk, val, opt, *len);
+					goto out;
+				}
+			}
 		}
 	}
 	ret = -ENOPROTOOPT;
  out:
-	read_unlock_bh(&nf_lock);
+	up(&nf_sockopt_mutex);
 	return ret;
+}
+
+int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
+		  int len)
+{
+	return nf_sockopt(sk, pf, val, opt, &len, 0);
+}
+
+int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
+{
+	return nf_sockopt(sk, pf, val, opt, len, 1);
 }
 
 static unsigned int nf_iterate(struct list_head *head,
diff -u --recursive --new-file v2.3.17/linux/net/core/sock.c linux/net/core/sock.c
--- v2.3.17/linux/net/core/sock.c	Tue Aug 31 17:29:15 1999
+++ linux/net/core/sock.c	Wed Sep  8 11:14:32 1999
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.85 1999/08/23 05:16:08 davem Exp $
+ * Version:	$Id: sock.c,v 1.86 1999/09/01 08:11:49 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.3.17/linux/net/decnet/dn_fib.c linux/net/decnet/dn_fib.c
--- v2.3.17/linux/net/decnet/dn_fib.c	Thu Aug 26 13:05:45 1999
+++ linux/net/decnet/dn_fib.c	Wed Sep  8 11:51:22 1999
@@ -24,7 +24,7 @@
 #include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/timer.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
 #include <net/neighbour.h>
diff -u --recursive --new-file v2.3.17/linux/net/decnet/dn_neigh.c linux/net/decnet/dn_neigh.c
--- v2.3.17/linux/net/decnet/dn_neigh.c	Thu Aug 26 13:05:45 1999
+++ linux/net/decnet/dn_neigh.c	Wed Sep  8 11:51:22 1999
@@ -30,8 +30,8 @@
 #include <linux/proc_fs.h>
 #include <linux/string.h>
 #include <linux/netfilter_decnet.h>
+#include <linux/spinlock.h>
 #include <asm/atomic.h>
-#include <asm/spinlock.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
 #include <net/dn.h>
diff -u --recursive --new-file v2.3.17/linux/net/decnet/dn_timer.c linux/net/decnet/dn_timer.c
--- v2.3.17/linux/net/decnet/dn_timer.c	Thu Aug 26 13:05:45 1999
+++ linux/net/decnet/dn_timer.c	Wed Sep  8 11:51:22 1999
@@ -20,8 +20,8 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/timer.h>
+#include <linux/spinlock.h>
 #include <net/sock.h>
-#include <asm/spinlock.h>
 #include <asm/atomic.h>
 #include <net/dn.h>
 
diff -u --recursive --new-file v2.3.17/linux/net/econet/econet.c linux/net/econet/econet.c
--- v2.3.17/linux/net/econet/econet.c	Tue Aug 31 17:29:15 1999
+++ linux/net/econet/econet.c	Wed Sep  8 11:51:22 1999
@@ -43,7 +43,7 @@
 #include <linux/if_ec.h>
 #include <net/udp.h>
 #include <net/ip.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
 
 static struct proto_ops econet_ops;
 static struct sock *econet_sklist;
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.17/linux/net/ipv4/af_inet.c	Tue Sep  7 12:14:07 1999
+++ linux/net/ipv4/af_inet.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.95 1999/08/30 10:17:00 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.97 1999/09/08 03:46:46 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.3.17/linux/net/ipv4/ip_output.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/ip_output.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) output module.
  *
- * Version:	$Id: ip_output.c,v 1.70 1999/08/31 07:03:39 davem Exp $
+ * Version:	$Id: ip_output.c,v 1.72 1999/09/07 02:31:15 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -345,7 +345,7 @@
 		if (skb2 == NULL)
 			return -ENOMEM;
 		if (sk)
-			skb_set_owner_w(skb, sk);
+			skb_set_owner_w(skb2, sk);
 		skb = skb2;
 		iph = skb->nh.iph;
 	}
@@ -386,7 +386,7 @@
 	struct iphdr *iph;
 
 	/* Make sure we can route this packet. */
-	rt = (struct rtable *)sk_dst_check(sk, 0);
+	rt = (struct rtable *)__sk_dst_check(sk, 0);
 	if (rt == NULL) {
 		u32 daddr;
 
@@ -403,10 +403,9 @@
 				    RT_TOS(sk->protinfo.af_inet.tos) | RTO_CONN | sk->localroute,
 				    sk->bound_dev_if))
 			goto no_route;
-		dst_clone(&rt->u.dst);
-		sk_dst_set(sk, &rt->u.dst);
+		__sk_dst_set(sk, &rt->u.dst);
 	}
-	skb->dst = &rt->u.dst;
+	skb->dst = dst_clone(&rt->u.dst);
 
 	if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto no_route;
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.3.17/linux/net/ipv4/ip_sockglue.c	Thu Aug 26 13:05:45 1999
+++ linux/net/ipv4/ip_sockglue.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		The IP to API glue.
  *		
- * Version:	$Id: ip_sockglue.c,v 1.44 1999/08/20 11:05:49 davem Exp $
+ * Version:	$Id: ip_sockglue.c,v 1.45 1999/09/06 04:58:03 davem Exp $
  *
  * Authors:	see ip.c
  *
@@ -598,13 +598,12 @@
  
 		default:
 #ifdef CONFIG_NETFILTER
-			release_sock(sk);
-			return nf_setsockopt(PF_INET, optname, optval, 
-					     (unsigned int)optlen);
+			err = nf_setsockopt(sk, PF_INET, optname, optval, 
+					    optlen);
 #else
 			err = -ENOPROTOOPT;
-			break;
 #endif
+			break;
 	}
 	release_sock(sk);
 	return err;
@@ -758,8 +757,17 @@
 			return put_user(len, optlen);
 		}
 		default:
+#ifdef CONFIG_NETFILTER
+			val = nf_getsockopt(sk, PF_INET, optname, optval, 
+					    &len);
+			release_sock(sk);
+			if (val >= 0)
+				val = put_user(len, optlen);
+			return val;
+#else
 			release_sock(sk);
 			return -ENOPROTOOPT;
+#endif
 	}
 	release_sock(sk);
 	
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.3.17/linux/net/ipv4/sysctl_net_ipv4.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipv4/sysctl_net_ipv4.c	Wed Sep  8 11:14:32 1999
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.39 1999/08/20 11:06:00 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.40 1999/09/07 02:31:17 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -150,6 +150,9 @@
 	{NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes",
 	 &sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL, 
 	 &proc_dointvec},
+	{NET_IPV4_TCP_KEEPALIVE_INTVL, "tcp_keepalive_intvl",
+	 &sysctl_tcp_keepalive_intvl, sizeof(int), 0644, NULL,
+	 &proc_dointvec_jiffies, &sysctl_jiffies},
 	{NET_IPV4_TCP_RETRIES1, "tcp_retries1",
 	 &sysctl_tcp_retries1, sizeof(int), 0644, NULL, &proc_dointvec_minmax, 
 	 &sysctl_intvec, NULL, NULL, &tcp_retr1_max},
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.17/linux/net/ipv4/tcp.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/tcp.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.149 1999/08/30 10:17:17 davem Exp $
+ * Version:	$Id: tcp.c,v 1.151 1999/09/07 02:31:21 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1580,7 +1580,7 @@
 	if(data_was_unread != 0) {
 		/* Unread data was tossed, zap the connection. */
 		tcp_set_state(sk, TCP_CLOSE);
-		tcp_send_active_reset(sk);
+		tcp_send_active_reset(sk, GFP_KERNEL);
 	} else if (tcp_close_state(sk,1)) {
 		/* We FIN if the application ate all the data before
 		 * zapping the connection.
@@ -1658,7 +1658,7 @@
 	if (old_state == TCP_LISTEN) {
 		tcp_close_pending(sk);
 	} else if (tcp_connected(old_state)) {
-		tcp_send_active_reset(sk);
+		tcp_send_active_reset(sk, GFP_KERNEL);
 		sk->err = ECONNRESET;
 	} else if (old_state == TCP_SYN_SENT)
 		sk->err = ECONNRESET;
@@ -1870,6 +1870,40 @@
 			tcp_push_pending_frames(sk, tp);
 		}
 		break;
+		
+	case TCP_KEEPIDLE:
+		if (val < 1 || val > MAX_TCP_KEEPIDLE)
+			err = -EINVAL;
+		else {
+			tp->keepalive_time = val * HZ;
+			if (sk->keepopen) {
+				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+				if (tp->keepalive_time > elapsed)
+					elapsed = tp->keepalive_time - elapsed;
+				else
+					elapsed = 0;
+				tcp_reset_keepalive_timer(sk, elapsed);
+			}
+		}
+		break;
+	case TCP_KEEPINTVL:
+		if (val < 1 || val > MAX_TCP_KEEPINTVL)
+			err = -EINVAL;
+		else
+			tp->keepalive_intvl = val * HZ;
+		break;
+	case TCP_KEEPCNT:
+		if (val < 1 || val > MAX_TCP_KEEPCNT)
+			err = -EINVAL;
+		else
+			tp->keepalive_probes = val;
+		break;
+	case TCP_SYNCNT:
+		if (val < 1 || val > MAX_TCP_SYNCNT)
+			err = -EINVAL;
+		else
+			tp->syn_retries = val;
+		break;
 
 	default:
 		err = -ENOPROTOOPT;
@@ -1903,6 +1937,30 @@
 		break;
 	case TCP_CORK:
 		val = (sk->nonagle == 2);
+		break;
+	case TCP_KEEPIDLE:
+		if (tp->keepalive_time)
+			val = tp->keepalive_time / HZ;
+		else
+			val = sysctl_tcp_keepalive_time / HZ;
+		break;
+	case TCP_KEEPINTVL:
+		if (tp->keepalive_intvl)
+			val = tp->keepalive_intvl / HZ;
+		else
+			val = sysctl_tcp_keepalive_intvl / HZ;
+		break;
+	case TCP_KEEPCNT:
+		if (tp->keepalive_probes)
+			val = tp->keepalive_probes;
+		else
+			val = sysctl_tcp_keepalive_probes;
+		break;
+	case TCP_SYNCNT:
+		if (tp->syn_retries)
+			val = tp->syn_retries;
+		else
+			val = sysctl_tcp_syn_retries;
 		break;
 	default:
 		return -ENOPROTOOPT;
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.17/linux/net/ipv4/tcp_input.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipv4/tcp_input.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.172 1999/08/23 06:30:35 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.173 1999/09/07 02:31:27 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2423,7 +2423,7 @@
 		newsk->timer.function = &tcp_keepalive_timer;
 		newsk->timer.data = (unsigned long) newsk;
 		if (newsk->keepopen)
-			tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time);
+			tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp));
 		newsk->socket = NULL;
 		newsk->sleep = NULL;
 
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.17/linux/net/ipv4/tcp_ipv4.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/tcp_ipv4.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.187 1999/08/31 07:03:48 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.189 1999/09/07 02:31:33 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -1822,7 +1822,7 @@
 
 int tcp_v4_rebuild_header(struct sock *sk)
 {
-	struct rtable *rt = (struct rtable *)sk->dst_cache;
+	struct rtable *rt = (struct rtable *)__sk_dst_get(sk);
 	__u32 new_saddr;
         int want_rewrite = sysctl_ip_dynaddr && sk->state == TCP_SYN_SENT;
 
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.3.17/linux/net/ipv4/tcp_output.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipv4/tcp_output.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.112 1999/08/23 06:30:37 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.113 1999/09/07 02:31:39 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -825,13 +825,13 @@
  * was unread data in the receive queue.  This behavior is recommended
  * by draft-ietf-tcpimpl-prob-03.txt section 3.10.  -DaveM
  */
-void tcp_send_active_reset(struct sock *sk)
+void tcp_send_active_reset(struct sock *sk, int priority)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sk_buff *skb;
 
 	/* NOTE: No TCP options attached and we never retransmit this. */
-	skb = alloc_skb(MAX_HEADER + sk->prot->max_header, GFP_KERNEL);
+	skb = alloc_skb(MAX_HEADER + sk->prot->max_header, priority);
 	if (!skb)
 		return;
 
@@ -947,7 +947,7 @@
 
 int tcp_connect(struct sock *sk, struct sk_buff *buff)
 {
-	struct dst_entry *dst = sk->dst_cache;
+	struct dst_entry *dst = __sk_dst_get(sk);
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
 	/* Reserve space for headers. */
diff -u --recursive --new-file v2.3.17/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.3.17/linux/net/ipv4/tcp_timer.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/tcp_timer.c	Wed Sep  8 11:14:32 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.67 1999/08/30 12:14:43 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.68 1999/09/07 02:31:43 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -25,6 +25,7 @@
 int sysctl_tcp_syn_retries = TCP_SYN_RETRIES; 
 int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME;
 int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES;
+int sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL;
 int sysctl_tcp_retries1 = TCP_RETR1;
 int sysctl_tcp_retries2 = TCP_RETR2;
 
@@ -183,7 +184,9 @@
 	}
 	
 	/* Have we tried to SYN too many times (repent repent 8)) */
-	if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {
+	if (sk->state == TCP_SYN_SENT && 
+	    ((!tp->syn_retries && tp->retransmits > sysctl_tcp_syn_retries) ||
+	      (tp->syn_retries && tp->retransmits > tp->syn_retries))) {
 		tcp_write_err(sk, 1);
 		/* Don't FIN, we got nothing back */
 	} else if (tp->retransmits > sysctl_tcp_retries2) {
@@ -593,7 +596,7 @@
 void tcp_set_keepalive(struct sock *sk, int val)
 {
 	if (val && !sk->keepopen)
-		tcp_reset_keepalive_timer(sk, sysctl_tcp_keepalive_time);
+		tcp_reset_keepalive_timer(sk, keepalive_time_when(&sk->tp_pinfo.af_tcp));
 	else if (!val)
 		tcp_delete_keepalive_timer(sk);
 }
@@ -619,25 +622,29 @@
 	if (!sk->keepopen)
 		goto out;
 
-	elapsed = sysctl_tcp_keepalive_time;
+	elapsed = keepalive_time_when(tp);
 	if (!((1<<sk->state) & (TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_FIN_WAIT2)))
 		goto resched;
 
 	elapsed = tcp_time_stamp - tp->rcv_tstamp;
 
-	if (elapsed >= sysctl_tcp_keepalive_time) {
-		if (tp->probes_out > sysctl_tcp_keepalive_probes) {
+	if (elapsed >= keepalive_time_when(tp)) {
+		if ((!tp->keepalive_probes && tp->probes_out >= sysctl_tcp_keepalive_probes) ||
+		     (tp->keepalive_probes && tp->probes_out >= tp->keepalive_probes)) {
+			tcp_send_active_reset(sk, GFP_ATOMIC);
 			tcp_write_err(sk, 1);
 			goto out;
 		}
 		tp->probes_out++;
 		tp->pending = TIME_KEEPOPEN;
 		tcp_write_wakeup(sk);
-		/* Randomize to avoid synchronization */
-		elapsed = (TCP_KEEPALIVE_PERIOD>>1) + (net_random()%TCP_KEEPALIVE_PERIOD);
+		elapsed = keepalive_intvl_when(tp);
 	} else {
-		/* It is tp->rcv_tstamp + sysctl_tcp_keepalive_time */
-		elapsed = sysctl_tcp_keepalive_time - elapsed;
+		/* It is tp->rcv_tstamp + keepalive_time_when(tp) */
+		if (keepalive_time_when(tp) > elapsed)
+			elapsed = keepalive_time_when(tp) - elapsed;
+		else
+			elapsed = 0;
 	}
 
 resched:
diff -u --recursive --new-file v2.3.17/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
--- v2.3.17/linux/net/irda/irda_device.c	Tue Aug 31 17:29:15 1999
+++ linux/net/irda/irda_device.c	Wed Sep  8 11:51:22 1999
@@ -36,12 +36,12 @@
 #include <linux/tty.h>
 #include <linux/kmod.h>
 #include <linux/wireless.h>
+#include <linux/spinlock.h>
 
 #include <asm/ioctls.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
-#include <asm/spinlock.h>
 
 #include <net/pkt_sched.h>
 
diff -u --recursive --new-file v2.3.17/linux/net/sched/sch_atm.c linux/net/sched/sch_atm.c
--- v2.3.17/linux/net/sched/sch_atm.c	Thu Aug 26 13:05:46 1999
+++ linux/net/sched/sch_atm.c	Wed Sep  8 11:14:32 1999
@@ -375,7 +375,7 @@
 	result = TC_POLICE_OK; /* be nice to gcc */
 	if (TC_H_MAJ(skb->priority) != sch->handle ||
 	    !(flow = (struct atm_flow_data *) atm_tc_get(sch,skb->priority)))
-		for (flow = p->link.next; flow; flow = flow->next)
+		for (flow = p->flows; flow; flow = flow->next)
 			if (flow->filter_list) {
 				result = tc_classify(skb,flow->filter_list,
 				    &res);
diff -u --recursive --new-file v2.3.17/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.17/linux/net/unix/af_unix.c	Tue Sep  7 12:14:07 1999
+++ linux/net/unix/af_unix.c	Wed Sep  8 11:14:32 1999
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.82 1999/08/30 10:17:37 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.84 1999/09/08 03:47:18 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
