diff -u --recursive --new-file v2.3.41/linux/CREDITS linux/CREDITS
--- v2.3.41/linux/CREDITS	Fri Jan 28 15:09:06 2000
+++ linux/CREDITS	Mon Jan 31 23:37:19 2000
@@ -287,6 +287,13 @@
 E: knan@mo.himolde.no
 D: Misc kernel hacks
 
+N: Andreas E. Bombe
+E: andreas.bombe@munich.netsurf.de
+W: http://home.pages.de/~andreas.bombe/
+P: 1024/04880A44 72E5 7031 4414 2EB6 F6B4  4CBD 1181 7032 0488 0A44
+D: IEEE 1394 subsystem rewrite and maintainer
+D: Texas Instruments PCILynx IEEE 1394 driver
+
 N: Zoltán Böszörményi
 E: zboszor@mail.externet.hu
 D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support
@@ -1306,6 +1313,14 @@
 S: North Little Rock, Arkansas 72115
 S: USA
 
+N: Stephan Linz
+E: linz@mazet.de
+E: Stephan.Linz@gmx.de
+W: http://www.crosswinds.net/~tuxer
+D: PCILynx patch to work with 1394a PHY and without local RAM
+S: (ask for current address)
+S: Germany
+
 N: Siegfried "Frieder" Loeffler (dg1sek)
 E: floeff@tunix.mathematik.uni-stuttgart.de, fl@LF.net
 W: http://www.mathematik.uni-stuttgart.de/~floeff
@@ -1508,13 +1523,14 @@
 S: Netherlands
 
 N: David S. Miller
-E: davem@dm.cobaltmicro.com
+E: davem@redhat.com
 D: Sparc and blue box hacker
 D: Vger Linux mailing list co-maintainer
 D: Linux Emacs elf/qmagic support + other libc/gcc things
 D: Yee bore de yee bore! ;-)
-S: 331 Santa Rosa Drive
-S: Los Gatos, California 95032
+S: 750 N. Shoreline Blvd.
+S: Apt. #111
+S: Mountain View, California 94043
 S: USA
 
 N: Rick Miller
@@ -1702,6 +1718,13 @@
 S: Tula 300000
 S: Russia
 
+N: Gordon Peters
+E: GordPeters@smarttech.com
+D: Isochronous receive for IEEE 1394 driver (OHCI module).
+D: Bugfixes for the aforementioned.
+S: Calgary, Alberta
+S: Canada
+
 N: Johnnie Peters
 E: jpeters@phx.mcd.mot.com
 D: Motorola PowerPC changes for PReP
@@ -1736,6 +1759,12 @@
 S: 13349 Berlin
 S: Germany
 
+N: Emanuel Pirker
+E: epirker@edu.uni-klu.ac.at
+D: AIC5800 IEEE 1394, RAW I/O on 1394
+D: Starter of Linux1394 effort
+S: ask per mail for current address
+
 N: Ken Pizzini
 E: ken@halcyon.com
 D: CDROM driver "sonycd535" (Sony CDU-535/531)
@@ -1851,6 +1880,13 @@
 S: 21 Rue Carnot
 S: 95170 Deuil La Barre
 S: France
+
+N: Sebastien Rougeaux
+E: Sebastien.Rougeaux@syseng.anu.edu.au
+D: IEEE 1394 OHCI module
+S: Research School of Information Science and Engineering
+S: The Australian National University, ACT 0200
+S: Australia
 
 N: Alessandro Rubini
 E: rubini@ipvvis.unipv.it
diff -u --recursive --new-file v2.3.41/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.41/linux/Documentation/Configure.help	Fri Jan 28 15:09:06 2000
+++ linux/Documentation/Configure.help	Mon Jan 31 10:19:21 2000
@@ -7504,14 +7504,16 @@
   Linux Token Ring Project site for the latest information at
   http://www.linuxtr.net
 
-Generic TMS380 Token Ring ISA/PCI adapter support
+Generic TMS380 Token Ring ISA/PCI/MCA/EISA adapter support
 CONFIG_TMS380TR
   This driver provides generic support for token ring adapters
   based on the Texas Instruments TMS380 series chipsets.  This
   includes the SysKonnect TR4/16(+) ISA (SK-4190), SysKonnect
   TR4/16(+) PCI (SK-4590), SysKonnect TR4/16 PCI (SK-4591),
-  Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and Intel 
-  TokenExpress 4/16 and PRO ISA adapters.
+  Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several
+  Madge adapters.  If selected, you will be asked to select
+  which cards to support below.  If you're using modules, each
+  class of card will be supported by a seperate module.
 
   If you have such an adapter and would like to use it, say Y or M and
   read the Token-Ring mini-HOWTO, available from
@@ -7520,9 +7522,28 @@
   Also read the file linux/Documentation/networking/tms380tr.txt or check
   http://www.auk.cx/tms380tr/
 
+Generic TMS380 PCI support
+CONFIG_TMSPCI
+  This tms380 module supports generic TMS380-based PCI cards.
+
+  These cards are known to work:
+     - Compaq 4/16 TR PCI
+     - SysKonnect TR4/16 PCI (SK-4590/SK-4591)
+     - Thomas-Conrad TC4048 PCI 4/16
+     - 3Com Token Link Velocity
+
+Madge Smart 16/4 PCI Mk2 support
+CONFIG_ABYSS
+  This tms380 module supports the Madge Smart 16/4 PCI Mk2 cards (51-02).
+
+Madge Smart 16/4 Ringode MicroChannel 
+CONFIG_MADGEMC
+  This tms380 module supports the Madge Smart 16/4 MC16 and MC32
+  MicroChannel adapters
+
 SMC ISA TokenRing adapter support
 CONFIG_SMCTR
-  This is support for the ISA SMC Token Ring cards, specifically
+  This is support for the ISA and MCA SMC Token Ring cards, specifically
   SMC TokenCard Elite (8115T) and SMC TokenCard Elite/A (8115T/A) adapters.
 
   If you have such an adapter and would like to use it, say Y or M and
@@ -7928,6 +7949,25 @@
   The module will be called usb-uhci.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
   
+UHCI (intel PIIX4, VIA, ...) alternate (JE) support?
+CONFIG_USB_UHCI_ALT
+  This is an alternate driver for UHCI support. It has been commonly
+  been referred to as the "JE driver".
+
+  The Universal Host Controller Interface is a standard by Intel for
+  accessing the USB hardware in the PC (which is also called the USB
+  host controller). If your USB host controller conforms to this
+  standard, say Y. All recent boards with Intel PCI chipsets (like
+  intel 430TX, 440FX, 440LX, 440BX, i810, i820) conform to this standard.
+  Also all VIA PCI chipsets (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo
+  Pro II or Apollo Pro 133).
+  If unsure, say Y.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called uhci.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+  
 OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support?
 CONFIG_USB_OHCI
   The Open Host Controller Interface is a standard by
@@ -8735,6 +8775,30 @@
   If you are not a part of a fairly large, distributed network, you
   probably do not need an automounter, and can say N here.
 
+  If you want to use the newer version of autofs with more features,
+  say N here and select automounter v4.
+
+Kernel automounter v4 support
+CONFIG_AUTOFS4_FS
+  The automounter is a tool to automatically mount remote filesystems
+  on demand. This implementation is partially kernel-based to reduce
+  overhead in the already-mounted case; this is unlike the BSD
+  automounter (amd), which is a pure user space daemon.
+
+  To use the automounter you need the user-space tools from
+  ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4 ; you also
+  want to answer Y to "NFS filesystem support", below.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called autofs4.o.  You will need to add "alias autofs autofs4" to
+  your modules configuration file.
+
+  If you are not a part of a fairly large, distributed network or don't
+  have a laptop which needs to dynamically reconfigure to the local
+  network, you probably do not need an automounter, and can say N here.
+
 EFS filesystem support (read only) (EXPERIMENTAL)
 CONFIG_EFS_FS
   EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk
@@ -10865,20 +10929,6 @@
   You can say M here to compile this driver as a module; the module is
   called sb.o.
 
-Generic OPL2/OPL3 FM synthesizer support
-CONFIG_SOUND_ADLIB
-  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-  Answering Y is usually a safe and recommended choice, however some
-  cards may have software (TSR) FM emulation. Enabling FM support with
-  these cards may cause trouble (I don't currently know of any such
-  cards, however). 
-
-  Please read the file Documentation/sound/OPL3 if your card has an
-  OPL3 chip.
-
-  If unsure, say Y.
-  
-
 #Loopback MIDI device support
 #CONFIG_SOUND_VMIDI
 ###
@@ -11154,8 +11204,16 @@
 
 FM synthesizer (YM3812/OPL-3) support
 CONFIG_SOUND_YM3812
-  Answer Y here, unless you know you will not need the option.
+  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+  Answering Y is usually a safe and recommended choice, however some
+  cards may have software (TSR) FM emulation. Enabling FM support with
+  these cards may cause trouble (I don't currently know of any such
+  cards, however).
+  Please read the file Documentation/sound/OPL3 if your card has an
+  OPL3 chip.
 
+  If unsure, say Y.
+ 
 Sun Audio support
 CONFIG_SUN_AUDIO
   This is support for the sound cards on Sun workstations. The code
@@ -11323,6 +11381,20 @@
   differs slightly from OSS/Free, so PLEASE READ
   Documentation/sound/sonicvibes.
 
+Trident 4DWave DX/NX or SiS 7018 PCI Audio Core
+CONFIG_SOUND_TRIDENT
+  Say Y or M if you have a PCI sound card utilizing the Trident
+  4DWave-DX/NX chipset or your mother board chipset has SiS 7018
+  built-in. The SiS 7018 PCI Audio Core is embedded in SiS960 
+  Super South Bridge and SiS540/630 Single Chipset.
+
+  Use lspci -n to find out if your sound card or chipset uses
+  Trident 4DWave or SiS 7018. PCI ID 1023:2000 or 1023:2001 stands
+  for Trident 4Dwave. PCI ID 1039:7018 stands for SiS7018.
+
+  This driver differs slightly from OSS/Free, so PLEASE READ the
+  comments at of driver/sound/trident.c
+
 Rockwell WaveArtist
 CONFIG_SOUND_WAVEARTIST
   Say Y here to include support for the Rockwell WaveArtist sound
@@ -13191,8 +13263,7 @@
   and makes it possible to use all existing applications that
   understands TTY's with an infrared link. Thus you should be able to
   use application like PPP, minicom and others. Enabling this option
-  will create two modules called ircomm and ircomm_tty. For more
-  information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/
+  will create two modules called ircomm and ircomm-tty.
 
 IrTTY IrDA Device Driver
 CONFIG_IRTTY_SIR
@@ -13242,11 +13313,10 @@
 
 NSC PC87108 IrDA Device Driver
 CONFIG_NSC_FIR
-  Say Y here if you want to build support for the NSC PC87108 IrDA
-  chipset. If you want to compile it as a module, say M here and
-  read Documentation/modules.txt. This drivers currently only supports
-  the ACTiSYS IR2000B ISA card and supports SIR, MIR and FIR (4Mbps)
-  speeds.
+  Say Y here if you want to build support for the NSC PC87108 and
+  PC87338 IrDA chipsets. If you want to compile it as a module, say M 
+  here and read Documentation/modules.txt. This driver supports SIR, 
+  MIR and FIR (4Mbps) speeds.
 
 Toshiba Type-O IR Port Device Driver
 CONFIG_TOSHIBA_FIR
@@ -13262,7 +13332,7 @@
   and read Documentation/modules.txt. The ESI dongle attaches to the
   normal 9-pin serial port connector, and can currently only be used
   by IrTTY. To activate support for ESI dongles you will have to
-  insert "irattach -d esi" in the /etc/irda/drivers script.
+  start irattach like this: "irattach -d esi".
 
 ACTiSYS IR-220L and IR220L+ dongle
 CONFIG_ACTISYS_DONGLE
@@ -13271,8 +13341,8 @@
   say M here and read Documentation/modules.txt. The ACTiSYS dongles
   attaches to the normal 9-pin serial port connector, and can
   currently only be used by IrTTY. To activate support for ACTiSYS
-  dongles you will have to insert "irattach -d actisys" or
-  "irattach -d actisys_plus" in the/etc/irda/drivers script.
+  dongles you will have to start irattach like this: 
+  "irattach -d actisys" or "irattach -d actisys+".
 
 Tekram IrMate 210B dongle
 CONFIG_TEKRAM_DONGLE
@@ -13281,7 +13351,7 @@
   and read Documentation/modules.txt. The Tekram dongle attaches to
   the normal 9-pin serial port connector, and can currently only be
   used by IrTTY. To activate support for Tekram dongles you will have
-  to insert "irattach -d tekram" in the /etc/irda/drivers script.
+  to start irattach like this: "irattach -d tekram".
 
 Greenwich GIrBIL dongle
 CONFIG_GIRBIL_DONGLE
@@ -13299,17 +13369,7 @@
   Documentation/modules.txt. The Parallax dongle attaches to the
   normal 9-pin serial port connector, and can currently only be used
   by IrTTY. To activate support for Parallax dongles you will have to
-  insert "irattach -d litelink" in the /etc/irda/drivers script.
-
-Adaptec Airport 1000 and 2000 dongle
-CONFIG_AIRPORT_DONGLE
-  Say Y here if you want to build support for the Adaptec Airport 1000
-  and 2000 dongles. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt. The module will be called
-  airport.o. The Airport dongle attaches to the normal 9-pin serial
-  port connector, and can currently only be used by IrTTY. To activate
-  support for Airport dongles you will have to insert "irattach -d
-  airport" in the /etc/irda/drivers script.
+  start irattach like this "irattach -d litelink".
 
 VME (Motorola and BVM) support
 CONFIG_VME
@@ -13427,6 +13487,7 @@
   The kHTTPd is experimental. Be careful when using it on a production
   machine. Also note that kHTTPd doesn't support virtual servers yet.
 
+#
 I2C support
 CONFIG_I2C
   I2C (pronounce: I-square-C) is a slow bus protocol developed by
@@ -13479,7 +13540,6 @@
   files, usually found in the /dev directory on your system. They
   make it possible to have user-space programs use the I2C bus.
 
-#
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
 #               Intel, IRQ, Linux, MSDOS, NetWare, NetWinder, NFS, 
diff -u --recursive --new-file v2.3.41/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.41/linux/MAINTAINERS	Fri Jan 28 15:09:06 2000
+++ linux/MAINTAINERS	Mon Jan 31 10:13:03 2000
@@ -456,6 +456,41 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+IEEE 1394 SUBSYSTEM
+P:	Andreas Bombe
+M:	andreas.bombe@munich.netsurf.de
+L:	linux1394-devel@eclipt.uni-klu.ac.at
+W:	http://eclipt.uni-klu.ac.at/ieee1394
+S:	Maintained
+
+IEEE 1394 AIC5800 DRIVER
+P:	Emanuel Pirker
+M:	epirker@edu.uni-klu.ac.at
+L:	linux1394-devel@eclipt.uni-klu.ac.at
+W:	http://eclipt.uni-klu.ac.at/ieee1394
+S:	Maintained
+
+IEEE 1394 OHCI DRIVER
+P:	Sebastien Rougeaux
+M:	sebastien.rougeaux@anu.edu.au
+L:	linux1394-devel@eclipt.uni-klu.ac.at
+W:	http://eclipt.uni-klu.ac.at/ieee1394
+S:	Maintained
+
+IEEE 1394 PCILYNX DRIVER
+P:	Andreas Bombe
+M:	andreas.bombe@munich.netsurf.de
+L:	linux1394-devel@eclipt.uni-klu.ac.at
+W:	http://eclipt.uni-klu.ac.at/ieee1394
+S:	Maintained
+
+IEEE 1394 RAW I/O DRIVER
+P:	Andreas Bombe
+M:	andreas.bombe@munich.netsurf.de
+L:	linux1394-devel@eclipt.uni-klu.ac.at
+W:	http://eclipt.uni-klu.ac.at/ieee1394
+S:	Maintained
+
 INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
 P:	Ingo Molnar
 M:	mingo@redhat.com
@@ -935,6 +970,12 @@
 L:	linux-net@vger.rutgers.edu
 L:	linux-tr@linuxtr.net
 S:	Maintained
+
+TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE
+P:      Ollie Lho  
+M:      ollie@sis.com.tw
+L:	linux-kernel@vger.rutgers.edu
+S:      Supported
 
 TMS380 TOKEN-RING NETWORK DRIVER
 P:	Adam Fritzler
diff -u --recursive --new-file v2.3.41/linux/Makefile linux/Makefile
--- v2.3.41/linux/Makefile	Fri Jan 28 15:09:06 2000
+++ linux/Makefile	Fri Jan 28 15:11:36 2000
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 41
+SUBLEVEL = 42
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.3.41/linux/arch/alpha/lib/csum_ipv6_magic.S linux/arch/alpha/lib/csum_ipv6_magic.S
--- v2.3.41/linux/arch/alpha/lib/csum_ipv6_magic.S	Mon Jan 12 14:49:36 1998
+++ linux/arch/alpha/lib/csum_ipv6_magic.S	Mon Jan 31 23:41:13 2000
@@ -4,7 +4,7 @@
  *
  * unsigned short csum_ipv6_magic(struct in6_addr *saddr,
  *                                struct in6_addr *daddr,
- *                                __u16 len,
+ *                                __u32 len,
  *                                unsigned short proto,
  *                                unsigned int csum);
  */
@@ -18,54 +18,74 @@
 
 	ldq	$0,0($16)	# e0    : load src & dst addr words
 	zapnot	$20,15,$20	# .. e1 : zero extend incoming csum
-	extwh	$18,7,$4	# e0    : byte swap len & proto while we wait
+	extqh	$18,7,$4	# e0    : byte swap len & proto while we wait
 	ldq	$1,8($16)	# .. e1 :
-	extbl	$18,1,$18	# e0    :
+
+	extbl	$18,1,$5	# e0	:
 	ldq	$2,0($17)	# .. e1 :
-	extwh	$19,7,$5	# e0    :
+	extbl	$18,2,$6	# e0 	:
 	ldq	$3,8($17)	# .. e1 :
-	extbl	$19,1,$19	# e0    :
-	or	$18,$4,$18	# .. e1 :
-	addq	$20,$0,$20	# e0    : begin summing the words
-	or	$19,$5,$19	# .. e1 :
-	sll	$18,48,$18	# e0    :
+
+	extbl	$18,3,$18	# e0	:
+	sra	$4,32,$4	# e0	:
+	sll	$5,16,$5	# e0	:
+	addq	$20,$0,$20	# .. e1 : begin summing the words
+
+	sll	$6,8,$6		# e0	:
 	cmpult	$20,$0,$0	# .. e1 :
+	extwh	$19,7,$7	# e0    :
+	or	$4,$18,$18	# .. e1 :
+
+	extbl	$19,1,$19	# e0    :
+	or	$5,$6,$5	# .. e1 :
+	or	$18,$5,$18	# e0    : len complete
+	or	$19,$7,$19	# .. e1 :
+
 	sll	$19,48,$19	# e0    :
 	addq	$20,$1,$20	# .. e1 :
-	sra	$18,32,$18	# e0    : len complete
-	cmpult	$20,$1,$1	# .. e1 :
 	sra	$19,32,$19	# e0    : proto complete
+	cmpult	$20,$1,$1	# .. e1 :
+
+	nop			# e0    :
 	addq	$20,$2,$20	# .. e1 :
 	cmpult	$20,$2,$2	# e0    :
 	addq	$20,$3,$20	# .. e1 :
+
 	cmpult	$20,$3,$3	# e0    :
 	addq	$20,$18,$20	# .. e1 :
 	cmpult	$20,$18,$18	# e0    :
 	addq	$20,$19,$20	# .. e1 :
+
 	cmpult	$20,$19,$19	# e0    :
 	addq	$0,$1,$0	# .. e1 : merge the carries back into the csum
 	addq	$2,$3,$2	# e0    :
 	addq	$18,$19,$18	# .. e1 :
+
 	addq	$0,$2,$0	# e0    :
 	addq	$20,$18,$20	# .. e1 :
 	addq	$0,$20,$0	# e0    :
 	unop			#       :
+
 	extwl	$0,2,$2		# e0    : begin folding the 64-bit value
 	zapnot	$0,3,$3		# .. e1 :
 	extwl	$0,4,$1		# e0    :
 	addq	$2,$3,$3	# .. e1 :
+
 	extwl	$0,6,$0		# e0    :
 	addq	$3,$1,$3	# .. e1 :
 	addq	$0,$3,$0	# e0    :
 	unop			#       :
+
 	extwl	$0,2,$1		# e0    : fold 18-bit value
 	zapnot	$0,3,$0		# .. e1 :
 	addq	$0,$1,$0	# e0    :
 	unop			#       :
+
 	extwl	$0,2,$1		# e0    : fold 17-bit value
 	zapnot	$0,3,$0		# .. e1 :
 	addq	$0,$1,$0	# e0    :
 	not	$0,$0		# e1    : and compliment.
+
 	zapnot	$0,3,$0		# e0    :
 	ret			# .. e1 :
 
diff -u --recursive --new-file v2.3.41/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.41/linux/arch/i386/config.in	Fri Jan 28 15:09:06 2000
+++ linux/arch/i386/config.in	Fri Jan 28 19:36:22 2000
@@ -22,7 +22,7 @@
 	 586/K5/5x86/6x86	CONFIG_M586	\
 	 Pentium/TSC		CONFIG_M586TSC	\
 	 PPro/6x86MX		CONFIG_M686 \
-	 K6/II/II		CONFIG_MK6 \
+	 K6/II/III		CONFIG_MK6 \
 	 Athlon                 CONFIG_MK7" PPro
 #
 # Define implied options from the CPU selection here
diff -u --recursive --new-file v2.3.41/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c
--- v2.3.41/linux/arch/i386/kernel/smpboot.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/i386/kernel/smpboot.c	Mon Jan 31 16:33:22 2000
@@ -710,7 +710,8 @@
 
 static void smp_tune_scheduling (void)
 {
-	unsigned long cachesize;
+	unsigned long cachesize;       /* kB   */
+	unsigned long bandwidth = 350; /* MB/s */
 	/*
 	 * Rough estimation for SMP scheduling, this is the number of
 	 * cycles it takes for a fully memory-limited process to flush
@@ -731,10 +732,12 @@
 		return;
 	} else {
 		cachesize = boot_cpu_data.x86_cache_size;
-		if (cachesize == -1)
-			cachesize = 8; /* Pentiums */
+		if (cachesize == -1) {
+			cachesize = 16; /* Pentiums, 2x8kB cache */
+			bandwidth = 100;
+		}
 
-		cacheflush_time = cpu_hz/1024*cachesize/5000;
+		cacheflush_time = (cpu_hz>>20) * (cachesize<<10) / bandwidth;
 	}
 
 	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
--- v2.3.41/linux/arch/m68k/amiga/amiints.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/amiga/amiints.c	Mon Jan 31 10:32:53 2000
@@ -364,7 +364,7 @@
 	intena = ami_intena_vals[irq];
 	custom.intreq = intena;
 
-	/* serve first fast handlers - there can only be one of these */
+	/* serve fast handler if present - there can only be one of these */
 	node = ami_irq_list[irq];
 
 	/*
@@ -392,7 +392,11 @@
 	 */
 	custom.intena = intena;
 	save_flags(flags);
+#if 0 /* def CPU_M68060_ONLY */
 	sti();
+#else
+	restore_flags((flags & ~0x0700) | (fp->sr & 0x0700));
+#endif
 
 	slow_nodes = node;
 	for (;;) {
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/atari/debug.c linux/arch/m68k/atari/debug.c
--- v2.3.41/linux/arch/m68k/atari/debug.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/atari/debug.c	Mon Jan 31 10:32:53 2000
@@ -311,10 +311,6 @@
 
 void __init atari_debug_init(void)
 {
-#ifdef CONFIG_KGDB
-    /* the m68k_debug_device is used by the GDB stub, do nothing here */
-    return;
-#endif
     if (!strcmp( m68k_debug_device, "ser" )) {
 	/* defaults to ser2 for a Falcon and ser1 otherwise */
 	strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" );
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/bvme6000/config.c linux/arch/m68k/bvme6000/config.c
--- v2.3.41/linux/arch/m68k/bvme6000/config.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/bvme6000/config.c	Mon Jan 31 10:32:53 2000
@@ -132,6 +132,7 @@
     bvme6000_set_vectors();
 #endif
 
+    mach_max_dma_address = 0xffffffff;
     mach_sched_init      = bvme6000_sched_init;
     mach_keyb_init       = bvme6000_keyb_init;
     mach_kbdrate         = bvme6000_kbdrate;
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.3.41/linux/arch/m68k/kernel/signal.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/kernel/signal.c	Mon Jan 31 10:32:53 2000
@@ -37,6 +37,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/highuid.h>
 
 #include <asm/setup.h>
 #include <asm/uaccess.h>
@@ -1048,6 +1049,7 @@
 				info.si_code = SI_USER;
 				info.si_pid = current->p_pptr->pid;
 				info.si_uid = current->p_pptr->uid;
+				info.si_uid16 = high2lowuid(current->p_pptr->uid);
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.3.41/linux/arch/m68k/kernel/traps.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/kernel/traps.c	Mon Jan 31 10:32:53 2000
@@ -37,9 +37,6 @@
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/siginfo.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
 
 /* assembler routines */
 asmlinkage void system_call(void);
@@ -766,11 +763,6 @@
 
 static void dump_stack(struct frame *fp)
 {
-#ifdef CONFIG_KGDB
-	/* This will never return to here, if kgdb has been initialized. And if
-	 * it returns from there, then to where the error happened... */
-	enter_kgdb( &fp->ptregs );
-#else
 	unsigned long *stack, *endstack, addr, module_start, module_end;
 	extern char _start, _etext;
 	int i;
@@ -868,15 +860,10 @@
 	for (i = 0; i < 10; i++)
 		printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]);
 	printk ("\n");
-#endif
 }
 
 void bad_super_trap (struct frame *fp)
 {
-#ifdef CONFIG_KGDB
-	/* Save the register dump if we'll enter kgdb anyways */
-	if (!kgdb_initialized) {
-#endif
 	console_verbose();
 	if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0]))
 		printk ("*** %s ***   FORMAT=%X\n",
@@ -906,9 +893,6 @@
 				fp->ptregs.pc);
 	}
 	printk ("Current process id is %d\n", current->pid);
-#ifdef CONFIG_KGDB
-	}
-#endif
 	die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
 }
 
@@ -1037,10 +1021,6 @@
 	if (!(fp->sr & PS_S))
 		return;
 
-#ifdef CONFIG_KGDB
-	/* Save the register dump if we'll enter kgdb anyways */
-	if (!kgdb_initialized) {
-#endif
 	console_verbose();
 	printk("%s: %08x\n",str,nr);
 	printk("PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
@@ -1052,9 +1032,6 @@
 
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 		current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
-#ifdef CONFIG_KGDB
-	}
-#endif
 	dump_stack((struct frame *)fp);
 	do_exit(SIGSEGV);
 }
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c
--- v2.3.41/linux/arch/m68k/mac/debug.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/m68k/mac/debug.c	Mon Jan 31 10:32:53 2000
@@ -397,10 +397,6 @@
 
 void __init mac_debug_init(void)
 {
-#ifdef CONFIG_KGDB
-    /* the m68k_debug_device is used by the GDB stub, do nothing here */
-    return;
-#endif
 #ifdef DEBUG_SERIAL
     if (   !strcmp( m68k_debug_device, "ser"  )
         || !strcmp( m68k_debug_device, "ser1" )) {
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/mvme147/config.c linux/arch/m68k/mvme147/config.c
--- v2.3.41/linux/arch/m68k/mvme147/config.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/mvme147/config.c	Mon Jan 31 10:32:53 2000
@@ -101,6 +101,7 @@
 
 void __init config_mvme147(void)
 {
+	mach_max_dma_address	= 0x01000000;
 	mach_sched_init		= mvme147_sched_init;
 	mach_keyb_init		= mvme147_keyb_init;
 	mach_kbdrate		= mvme147_kbdrate;
diff -u --recursive --new-file v2.3.41/linux/arch/m68k/mvme16x/config.c linux/arch/m68k/mvme16x/config.c
--- v2.3.41/linux/arch/m68k/mvme16x/config.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/m68k/mvme16x/config.c	Mon Jan 31 10:32:53 2000
@@ -145,6 +145,7 @@
     p_bdid p = &mvme_bdid;
     char id[40];
 
+    mach_max_dma_address = 0xffffffff;
     mach_sched_init      = mvme16x_sched_init;
     mach_keyb_init       = mvme16x_keyb_init;
     mach_kbdrate         = mvme16x_kbdrate;
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.3.41/linux/arch/sparc/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/Makefile	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.44 1999/08/19 06:22:20 jj Exp $
+# $Id: Makefile,v 1.45 2000/01/29 01:08:48 anton Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -43,14 +43,6 @@
 
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \
 	$(TOPDIR)/arch/sparc/lib/lib.a
-
-ifdef CONFIG_AP1000
-SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp
-CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \
-	      $(TOPDIR)/mpp/mpplib.o $(CORE_FILES) 
-DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a
-CFLAGS := $(CFLAGS) -D__MPP__=1
-endif
 
 # This one has to come last
 SUBDIRS += arch/sparc/boot
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/Makefile linux/arch/sparc/ap1000/Makefile
--- v2.3.41/linux/arch/sparc/ap1000/Makefile	Mon Dec 20 18:48:21 1999
+++ linux/arch/sparc/ap1000/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-# Makefile for the AP1000 files in the Linux kernel
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-.S.s:
-	$(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
-.S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
-
-all: ap1000lib.o
-
-O_TARGET := ap1000lib.o
-O_OBJS   := bnet.o timer.o util.o dma.o kgdb.o irq.o \
-	msc.o hw.o tnet.o sync.o mpp.o \
-	apmmu.o aplib.o approm.o
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/apinline.h linux/arch/sparc/ap1000/apinline.h
--- v2.3.41/linux/arch/sparc/ap1000/apinline.h	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/apinline.h	Wed Dec 31 16:00:00 1969
@@ -1,86 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* inline utilities to support the AP1000 code */
-
-#if 0
-/* MMU bypass access */
-
-static inline unsigned long phys_9_in(unsigned long paddr)
-{
-	unsigned long word;
-
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (word) :
-			     "r" (paddr), "i" (0x29) :
-			     "memory");
-	return word;
-}
-
-static inline void phys_9_out(unsigned long paddr, unsigned long word)
-{
-	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-			     "r" (word), "r" (paddr), "i" (0x29) :
-			     "memory");
-}
-
-static inline unsigned long phys_b_in(unsigned long paddr)
-{
-	unsigned long word;
-
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (word) :
-			     "r" (paddr), "i" (0x2b) :
-			     "memory");
-	return word;
-}
-
-static inline void phys_b_out(unsigned long paddr, unsigned long word)
-{
-	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-			     "r" (word), "r" (paddr), "i" (0x2b) :
-			     "memory");
-}
-
-static inline unsigned long phys_c_in(unsigned long paddr)
-{
-	unsigned long word;
-
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (word) :
-			     "r" (paddr), "i" (0x2b) :
-			     "memory");
-	return word;
-}
-
-static inline void phys_c_out(unsigned long paddr, unsigned long word)
-{
-	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-			     "r" (word), "r" (paddr), "i" (0x2b) :
-			     "memory");
-}
-
-#undef BIF_IN
-#undef BIF_OUT
-#undef DMA_IN
-#undef DMA_OUT
-#undef MSC_IN
-#undef MSC_OUT
-#undef MC_IN
-#undef MC_OUT
-
-#define BIF_IN(reg) phys_9_in(reg)
-#define BIF_OUT(reg,v) phys_9_out(reg,v)
-#define DMA_IN(reg) phys_9_in(reg)
-#define DMA_OUT(reg,v) phys_9_out(reg,v)
-#define MC_IN(reg) phys_b_in((reg) - MC_BASE0)
-#define MC_OUT(reg,v) phys_b_out((reg) - MC_BASE0,v)
-#define MSC_IN(reg) phys_c_in((reg) - MSC_BASE0)
-#define MSC_OUT(reg,v) phys_c_out((reg) - MSC_BASE0,v)
-#endif
-
-
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/aplib.c linux/arch/sparc/ap1000/aplib.c
--- v2.3.41/linux/arch/sparc/ap1000/aplib.c	Mon Jul  5 20:35:17 1999
+++ linux/arch/sparc/ap1000/aplib.c	Wed Dec 31 16:00:00 1969
@@ -1,496 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-
-/* kernel based aplib.
-
-   This was initially implemented in user space, but we eventually
-   relented when we discovered some really nasty MSC hardware bugs and
-   decided to disallow access to the device registers by users. Pity :-(
-
-   Andrew Tridgell, November 1996 
-*/
-
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
- #include <asm/ap1000/pgtapmmu.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/aplib.h>
-
-
-extern int *tnet_rel_cid_table;
-extern unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy;
-
-
-/* this is used to stop the task hogging the MSC while paging in data */
-static inline void page_in(char *addr,long size)
-{
-	unsigned sum = 0;
-	while (size > 0) {
-		sum += *(volatile char *)addr;
-		addr += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-}
-
-
-/* this sets up the aplib structures using info passed in from user space
-   it should only be called once, and should be the first aplib call 
-   it should be followed by APLIB_SYNC 
-   */
-static inline int aplib_init(struct aplib_init *init)
-{
-	struct aplib_struct *aplib;
-	int error,i;
-	int old_uid;
-
-	error = verify_area(VERIFY_READ,init,sizeof(*init));
-	if (error) return error;
-	error = verify_area(VERIFY_READ,init->phys_cells,
-			    sizeof(int)*init->numcells);
-	if (error) return error;
-	error = verify_area(VERIFY_WRITE,
-			    init->ringbuffer,
-			    init->ringbuf_size * sizeof(int));
-	if (error) return error;
-	error = verify_area(VERIFY_WRITE,
-			    (char *)APLIB_PAGE_BASE,
-			    APLIB_PAGE_LEN);
-	if (error) return error;
-
-	if (!MPP_IS_PAR_TASK(current->taskid))
-		return -EINVAL;
-
-	if (current->aplib)
-		return -EINVAL;
-
-	aplib = current->aplib = (struct aplib_struct *)APLIB_PAGE_BASE;
-
-	/* lock the aplib structure in memory */
-	old_uid = current->euid;
-	current->euid = 0;
-	memset(aplib,0,APLIB_PAGE_LEN);
-	error = sys_mlock(aplib,APLIB_PAGE_LEN);
-	current->euid = old_uid;
-	if (error) {
-		printk("mlock1 failed\n");
-		return error;
-	}
-
-	/* lock the ringbuffer in memory */
-	old_uid = current->euid;
-	current->euid = 0;
-	memset(init->ringbuffer,0,init->ringbuf_size*4);
-	error = sys_mlock(init->ringbuffer,init->ringbuf_size*4);
-	current->euid = old_uid;
-	if (error) {
-		printk("mlock2 failed\n");
-		return error;
-	}
-
-	aplib->ringbuf = init->ringbuffer;
-	aplib->ringbuf_size = init->ringbuf_size;
-	aplib->numcells = init->numcells;
-	aplib->cid = init->cid;
-	aplib->tid = current->taskid;
-	aplib->numcells_x = init->numcells_x;
-	aplib->numcells_y = init->numcells_y;
-	aplib->cidx = init->cid % init->numcells_x;
-	aplib->cidy = init->cid / init->numcells_x;
-
-	aplib->physical_cid = (unsigned *)(aplib+1);
-	aplib->rel_cid      = aplib->physical_cid + init->numcells;
-
-	if ((char *)(aplib->rel_cid + init->numcells) >
-	    (char *)(APLIB_PAGE_BASE + APLIB_PAGE_LEN)) {
-		return -ENOMEM;
-	}
-
-	memcpy(aplib->physical_cid,init->phys_cells,
-	       sizeof(int)*init->numcells);
-
-	/* initialise the relative cid table */
-	for (i=0;i<aplib->numcells;i++) 
-		aplib->rel_cid[i] = 
-			tnet_rel_cid_table[aplib->physical_cid[i]];
-
-	return 0;
-}
-
-
-/* n == which sync line (ignored)
-   returns logical or of the stat values across the cells (1 bit resolution) 
-
-   This has to be done very carefully as the tasks can startup on the cells
-   in any order, so we don't know which tasks have started up when this
-   is called
-*/
-static inline int aplib_sync(int n,int stat)
-{
-	struct aplib_struct *aplib = current->aplib;
-	static int sync_flags[MPP_NUM_TASKS];
-	int i,err;
-	int tsk = current->taskid;
-
-	stat &= 1;
-
-	if (aplib->numcells < 2) 
-		return stat;
-
-	tsk -= MPP_TASK_BASE;
-
-	if (aplib->cid == 0) {
-		if ((err=wait_on_int(&sync_flags[tsk],
-				     aplib->numcells-1,5)))
-			return err;
-		sync_flags[tsk] = 0;
-		if (aplib->numcells == _ncel) {
-			ap_bput(0,0,0,(u_long)&sync_flags[tsk],0);
-		} else {
-			for (i=1;i<aplib->numcells;i++)
-				ap_put(aplib->physical_cid[i],
-				       0,0,0,(u_long)&sync_flags[tsk],0);
-		}
-	} else {
-		ap_put(aplib->physical_cid[0],
-		       0,0,0,(u_long)&sync_flags[tsk],0);
-		if ((err=wait_on_int(&sync_flags[tsk],1,5)))
-			return err;
-		sync_flags[tsk] = 0;
-	}
-
-	/* I haven't written the xy_ calls yet ... */
-	/* aplib_xy_ior(stat,&stat); */
-
-	return stat;
-}
-
-
-
-static inline void _putget(unsigned q,
-			   unsigned rcell,
-			   unsigned *src_addr,
-			   unsigned size,unsigned *dest_addr,
-			   unsigned *dest_flag,unsigned *src_flag)
-{
-	unsigned flags;
-	volatile unsigned *entry = (volatile unsigned *)q;
-
-	save_flags(flags); cli();
-
-	*entry = rcell;
-	*entry = size;
-	*entry = (unsigned)dest_addr;
-	*entry = 0;
-	*entry = (unsigned)dest_flag;
-	*entry = (unsigned)src_flag;
-	*entry = (unsigned)src_addr;
-	*entry = 0;
-
-	restore_flags(flags);
-}
-
-
-/* a basic put() operation. Note the avoidance of odd word boundaries
-   and transfers sizes beyond what the hardware can deal with */
-static inline int aplib_put(struct aplib_putget *put)
-{
-	int error;
-	struct aplib_struct *aplib = current->aplib;
-
-	error = verify_area(VERIFY_WRITE,put,sizeof(*put));
-	if (error) return error;
-
-	if (put->cid >= aplib->numcells) 
-		return -EINVAL;
-
-	do {
-		int n;
-
-		if (put->size && (((unsigned)put->src_addr) & 4)) {
-			n = 1;
-		} else if (put->size > MAX_PUT_SIZE) {
-			n = MAX_PUT_SIZE;
-		} else {
-			n = put->size;
-		}
-
-		put->size -= n;
-
-		page_in((char *)put->src_addr,n<<2);
-
-		_putget(MSC_PUT_QUEUE,
-			aplib->rel_cid[put->cid],
-			put->src_addr,
-			n,
-			put->dest_addr,
-			put->size?0:put->dest_flag,
-			put->size?0:put->src_flag);
-
-		put->dest_addr += n;
-		put->src_addr += n;
-	} while (put->size);
-
-	if (put->ack) {
-		aplib->ack_request++;
-		_putget(MSC_GET_QUEUE,
-			aplib->rel_cid[put->cid], 
-			0, 0, 0,
-			&aplib->ack_flag, 0);
-	}
-
-	return 0;
-}
-
-
-/* a basic get() operation */
-static inline int aplib_get(struct aplib_putget *get)
-{
-	struct aplib_struct *aplib = current->aplib;
-	int error = verify_area(VERIFY_WRITE,get,sizeof(*get));
-	if (error) return error;
-
-	if (get->cid >= aplib->numcells) 
-		return -EINVAL;
-
-	do {
-		int n;
-
-		if (get->size && (((unsigned)get->src_addr) & 4)) {
-			n = 1;
-		} else if (get->size > MAX_PUT_SIZE) {
-			n = MAX_PUT_SIZE;
-		} else {
-			n = get->size;
-		}
-
-		get->size -= n;
-
-		page_in((char *)get->dest_addr,n<<2);
-
-		_putget(MSC_GET_QUEUE,
-			aplib->rel_cid[get->cid],
-			get->src_addr,
-			n,
-			get->dest_addr,
-			get->size?0:get->dest_flag,
-			get->size?0:get->src_flag);
-		
-		get->dest_addr += n;
-		get->src_addr += n;
-	} while (get->size);
-
-	return 0;
-}
-
-
-/* we have received a protocol message - now do the get 
- This function is called from interrupt level with interrupts
- disabled 
-
- note that send->size is now in words
-*/
-void aplib_bigrecv(unsigned *msgp)
-{
-	struct aplib_struct *aplib;
-	struct aplib_send *send = (struct aplib_send *)(msgp+2);
-	unsigned tid = (msgp[1]&0x3FF);
-	unsigned cid = (msgp[0]>>22)&0x1FF;
-	unsigned octx, ctx;
-	struct task_struct *tsk;
-	unsigned room;
-
-	tsk = task[tid];
-	if (!tsk || !tsk->aplib)
-		return;
-
-	octx = apmmu_get_context();
-	ctx = MPP_TASK_TO_CTX(tid);
-	if (octx != ctx)
-		apmmu_set_context(ctx);
-	aplib = tsk->aplib;
-
-	if (aplib->write_pointer < aplib->read_pointer) 
-		room = aplib->read_pointer - (aplib->write_pointer+1);
-	else
-		room = aplib->ringbuf_size - 
-			((aplib->write_pointer+1)-aplib->read_pointer);
-
-	if (room < (send->size+2)) {
-		send_sig(SIGLOST,tsk,1);		
-		goto finished;
-	}
-
-	aplib->ringbuf[aplib->write_pointer++] = send->info1;
-	aplib->ringbuf[aplib->write_pointer++] = send->info2;
-
-	/* now finally do the get() */
-	_putget(MSC_GET_QUEUE,
-		aplib->rel_cid[cid],
-		send->src_addr,
-		send->size,
-		&aplib->ringbuf[aplib->write_pointer],
-		&aplib->rbuf_flag2,
-		send->flag_addr);
-
-	aplib->write_pointer += send->size;
-	if (aplib->write_pointer >= aplib->ringbuf_size)
-		aplib->write_pointer -= aplib->ringbuf_size;
-	
-finished:
-        if (octx != ctx)
-                apmmu_set_context(octx);
-}
-
-
-/* note the 8 byte alignment fix for the MSC bug */
-static inline int aplib_send(struct aplib_send *send)
-{
-	struct aplib_struct *aplib = current->aplib;
-	int wordSize;
-	int byteAlign, byteFix;
-	u_long src;
-	u_long info1, info2;
-	volatile unsigned *q = (volatile unsigned *)MSC_SEND_QUEUE_S;
-	extern long system_recv_flag;
-	int error;
-	unsigned flags, rcell;
-	unsigned flag_ptr;
-
-	error = verify_area(VERIFY_WRITE,send,sizeof(*send));
-	if (error) return error;
-
-	if (send->cid >= aplib->numcells) 
-		return -EINVAL;
-
-	if (send->tag == RBUF_SYSTEM || send->tag == RBUF_BIGSEND)
-		return -EINVAL;
-
-	error = verify_area(VERIFY_READ,(char *)send->src_addr,send->size);
-	if (error) return error;
-
-	page_in((char *)send->src_addr,send->size);
-
-	rcell = aplib->rel_cid[send->cid];
-
-	byteAlign = send->src_addr & 0x3;
-	byteFix = send->size & 0x3;
-
-	wordSize = (send->size + byteAlign + 3) >> 2;
-
-	src = send->src_addr & ~3;
-
-	/* this handles the MSC alignment bug */
-	if (wordSize > 1 &&
-	    (src & 4)) {
-		info1 |= 0x80000000;
-		src -= 4;
-		wordSize++;
-	}
-	
-	info1 = (aplib->cid<<22) | (byteFix<<20) | wordSize;
-	info2 = (send->tag<<28) | (byteAlign<<26) | 
-		(send->type<<10) | aplib->tid;
-	flag_ptr = (unsigned)&send->flag;
-
-	if (send->size > SMALL_SEND_THRESHOLD) {
-		send->info1 = info1;
-		send->info2 = info2;
-		send->size = wordSize;
-		send->src_addr = src;
-		send->flag_addr = (unsigned)&send->flag;
-		flag_ptr = 0;
-
-		wordSize = sizeof(*send)>>2;
-		src = (unsigned)send;
-		
-		info1 = (aplib->cid<<22) | wordSize;
-		info2 = (RBUF_BIGSEND<<28) | aplib->tid;
-	}
-
-	save_flags(flags); cli();
-
-	*q = rcell;
-	*q = wordSize;
-	*q = (u_long)&system_recv_flag;
-	*q = flag_ptr;
-	*q = (u_long)src;
-	*q = 0;
-	*q = info1;
-	*q = info2;
-
-	restore_flags(flags);
-
-	return 0;
-}
-
-
-static inline int aplib_probe(void)
-{
-	tnet_check_completion();
-	return 0;
-}
-
-static inline int aplib_poll(unsigned counter)
-{
-	struct aplib_struct *aplib = current->aplib;
-
-	while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) {
-		tnet_check_completion();
-		if (current->need_resched)
-			break;
-		if (signal_pending(current)) break;
-	}
-	return 0;
-}
-
-int sys_aplib(unsigned call,int a1,int a2,int a3,int a4)
-{
-
-	if (!current->aplib && call != APLIB_INIT)
-		return -EINVAL;
-
-	switch (call) {
-	case APLIB_INIT:
-		return aplib_init((struct aplib_init *)a1);
-
-	case APLIB_SYNC:
-		return aplib_sync(a1,a2);
-
-	case APLIB_PUT:
-		return aplib_put((struct aplib_putget *)a1);
-
-	case APLIB_GET:
-		return aplib_get((struct aplib_putget *)a1);
-
-	case APLIB_SEND:
-		return aplib_send((struct aplib_send *)a1);
-
-	case APLIB_PROBE:
-		return aplib_probe();
-
-	case APLIB_POLL:
-		return aplib_poll((unsigned)a1);
-	}
-
-	return -EINVAL;
-}
-
-
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/apmmu.c linux/arch/sparc/ap1000/apmmu.c
--- v2.3.41/linux/arch/sparc/ap1000/apmmu.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc/ap1000/apmmu.c	Wed Dec 31 16:00:00 1969
@@ -1,1144 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* 
- * apmmu.c:  mmu routines for the AP1000
- *
- * based on srmmu.c 
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/kdebug.h>
-#include <asm/vaddrs.h>
-#include <asm/traps.h>
-#include <asm/smp.h>
-#include <asm/mbus.h>
-#include <asm/cache.h>
-#include <asm/oplib.h>
-#include <asm/sbus.h>
-#include <asm/iommu.h>
-#include <asm/asi.h>
-#include <asm/msi.h>
-#include <asm/a.out.h>
-#include <asm/ap1000/pgtapmmu.h>
-#include <asm/viking.h>
-
-
-extern void mc_tlb_flush_all(void);
-
-static void poke_viking(void);
-static void viking_flush_tlb_page_for_cbit)(unsigned long page);
-
-static struct apmmu_stats {
-	int invall;
-	int invpg;
-	int invrnge;
-	int invmm;
-} module_stats;
-
-static char *apmmu_name;
-
-static ctxd_t *apmmu_ctx_table_phys;
-static ctxd_t *apmmu_context_table;
-
-static unsigned long ap_mem_size;
-static unsigned long mempool;
-
-
-static inline unsigned long apmmu_v2p(unsigned long vaddr)
-{
-	if (KERNBASE <= vaddr &&
-	    (KERNBASE + ap_mem_size > vaddr)) {
-		return (vaddr - KERNBASE);
-	}
-	return 0xffffffffUL;
-}
-
-static inline unsigned long apmmu_p2v(unsigned long paddr)
-{
-	if (ap_mem_size > paddr)
-		return (paddr + KERNBASE);
-	return 0xffffffffUL;
-}
-
-/* In general all page table modifications should use the V8 atomic
- * swap instruction.  This insures the mmu and the cpu are in sync
- * with respect to ref/mod bits in the page tables.
- */
-static inline unsigned long apmmu_swap(unsigned long *addr, unsigned long value)
-{
-	/* the AP1000 has its memory on bus 8, not 0 like suns do */
-	if ((value&0xF0000000) == 0)
-		value |= MEM_BUS_SPACE<<28;
-	__asm__ __volatile__("swap [%2], %0\n\t" :
-			     "=&r" (value) :
-			     "0" (value), "r" (addr));
-	return value;
-}
-
-/* Functions really use this, not apmmu_swap directly. */
-#define apmmu_set_entry(ptr, newentry) \
-        apmmu_swap((unsigned long *) (ptr), (newentry))
-
-
-/* The very generic APMMU page table operations. */
-static unsigned int apmmu_pmd_align(unsigned int addr) { return APMMU_PMD_ALIGN(addr); }
-static unsigned int apmmu_pgdir_align(unsigned int addr) { return APMMU_PGDIR_ALIGN(addr); }
-
-static inline int apmmu_device_memory(unsigned long x) 
-{
-	return ((x & 0xF0000000) != 0);
-}
-
-static unsigned long apmmu_pgd_page(pgd_t pgd)
-{ return apmmu_device_memory(pgd_val(pgd))?~0:apmmu_p2v((pgd_val(pgd) & APMMU_PTD_PMASK) << 4); }
-
-static unsigned long apmmu_pmd_page(pmd_t pmd)
-{ return apmmu_device_memory(pmd_val(pmd))?~0:apmmu_p2v((pmd_val(pmd) & APMMU_PTD_PMASK) << 4); }
-
-static unsigned long apmmu_pte_page(pte_t pte)
-{ return apmmu_device_memory(pte_val(pte))?~0:apmmu_p2v((pte_val(pte) & APMMU_PTE_PMASK) << 4); }
-
-static int apmmu_pte_none(pte_t pte)          
-{ return !(pte_val(pte) & 0xFFFFFFF); }
-
-static int apmmu_pte_present(pte_t pte)
-{ return ((pte_val(pte) & APMMU_ET_MASK) == APMMU_ET_PTE); }
-
-static void apmmu_pte_clear(pte_t *ptep)      { set_pte(ptep, __pte(0)); }
-
-static int apmmu_pmd_none(pmd_t pmd)          
-{ return !(pmd_val(pmd) & 0xFFFFFFF); }
-
-static int apmmu_pmd_bad(pmd_t pmd)
-{ return (pmd_val(pmd) & APMMU_ET_MASK) != APMMU_ET_PTD; }
-
-static int apmmu_pmd_present(pmd_t pmd)
-{ return ((pmd_val(pmd) & APMMU_ET_MASK) == APMMU_ET_PTD); }
-
-static void apmmu_pmd_clear(pmd_t *pmdp)      { set_pte((pte_t *)pmdp, __pte(0)); }
-
-static int apmmu_pgd_none(pgd_t pgd)          
-{ return !(pgd_val(pgd) & 0xFFFFFFF); }
-
-static int apmmu_pgd_bad(pgd_t pgd)
-{ return (pgd_val(pgd) & APMMU_ET_MASK) != APMMU_ET_PTD; }
-
-static int apmmu_pgd_present(pgd_t pgd)
-{ return ((pgd_val(pgd) & APMMU_ET_MASK) == APMMU_ET_PTD); }
-
-static void apmmu_pgd_clear(pgd_t * pgdp)     { set_pte((pte_t *)pgdp, __pte(0)); }
-
-static pte_t apmmu_pte_mkwrite(pte_t pte)     { return __pte(pte_val(pte) | APMMU_WRITE);}
-static pte_t apmmu_pte_mkdirty(pte_t pte)     { return __pte(pte_val(pte) | APMMU_DIRTY);}
-static pte_t apmmu_pte_mkyoung(pte_t pte)     { return __pte(pte_val(pte) | APMMU_REF);}
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-static pte_t apmmu_mk_pte(unsigned long page, pgprot_t pgprot)
-{ return __pte(((apmmu_v2p(page)) >> 4) | pgprot_val(pgprot)); }
-
-static pte_t apmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot)
-{ return __pte(((page) >> 4) | pgprot_val(pgprot)); }
-
-static pte_t apmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space)
-{
-	return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot));
-}
-
-static void apmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
-{ 
-	set_pte((pte_t *)ctxp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pgdp) >> 4)));
-}
-
-static void apmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp)
-{
-	set_pte((pte_t *)pgdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) pmdp) >> 4)));
-}
-
-static void apmmu_pmd_set(pmd_t * pmdp, pte_t * ptep)
-{
-	set_pte((pte_t *)pmdp, (APMMU_ET_PTD | (apmmu_v2p((unsigned long) ptep) >> 4)));
-}
-
-static pte_t apmmu_pte_modify(pte_t pte, pgprot_t newprot)
-{
-	return __pte((pte_val(pte) & APMMU_CHG_MASK) | pgprot_val(newprot));
-}
-
-/* to find an entry in a top-level page table... */
-static pgd_t *apmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
-{
-	return mm->pgd + ((address >> APMMU_PGDIR_SHIFT) & (APMMU_PTRS_PER_PGD - 1));
-}
-
-/* Find an entry in the second-level page table.. */
-static pmd_t *apmmu_pmd_offset(pgd_t * dir, unsigned long address)
-{
-	return (pmd_t *) apmmu_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1));
-}
-
-/* Find an entry in the third-level page table.. */ 
-static pte_t *apmmu_pte_offset(pmd_t * dir, unsigned long address)
-{
-	return (pte_t *) apmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1));
-}
-
-/* This must update the context table entry for this process. */
-static void apmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
-{
-	if(tsk->mm->context != NO_CONTEXT) {
-		flush_cache_mm(current->mm);
-		apmmu_ctxd_set(&apmmu_context_table[tsk->mm->context], pgdp);
-		flush_tlb_mm(current->mm);
-	}
-}
-
-
-/* Accessing the MMU control register. */
-static inline unsigned int apmmu_get_mmureg(void)
-{
-        unsigned int retval;
-	__asm__ __volatile__("lda [%%g0] %1, %0\n\t" :
-			     "=r" (retval) :
-			     "i" (ASI_M_MMUREGS));
-	return retval;
-}
-
-static inline void apmmu_set_mmureg(unsigned long regval)
-{
-	__asm__ __volatile__("sta %0, [%%g0] %1\n\t" : :
-			     "r" (regval), "i" (ASI_M_MMUREGS) : "memory");
-
-}
-
-static inline void apmmu_set_ctable_ptr(unsigned long paddr)
-{
-	paddr = ((paddr >> 4) & APMMU_CTX_PMASK);
-        paddr |= (MEM_BUS_SPACE<<28);
-	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-			     "r" (paddr), "r" (APMMU_CTXTBL_PTR),
-			     "i" (ASI_M_MMUREGS) :
-			     "memory");
-}
-
-static inline void apmmu_flush_whole_tlb(void)
-{
-	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
-			     "r" (0x400),        /* Flush entire TLB!! */
-			     "i" (ASI_M_FLUSH_PROBE) : "memory");
-
-}
-
-/* These flush types are not available on all chips... */
-static inline void apmmu_flush_tlb_ctx(void)
-{
-	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
-			     "r" (0x300),        /* Flush TLB ctx.. */
-			     "i" (ASI_M_FLUSH_PROBE) : "memory");
-
-}
-
-static inline void apmmu_flush_tlb_region(unsigned long addr)
-{
-	addr &= APMMU_PGDIR_MASK;
-	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
-			     "r" (addr | 0x200), /* Flush TLB region.. */
-			     "i" (ASI_M_FLUSH_PROBE) : "memory");
-
-}
-
-
-static inline void apmmu_flush_tlb_segment(unsigned long addr)
-{
-	addr &= APMMU_PMD_MASK;
-	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
-			     "r" (addr | 0x100), /* Flush TLB segment.. */
-			     "i" (ASI_M_FLUSH_PROBE) : "memory");
-
-}
-
-static inline void apmmu_flush_tlb_page(unsigned long page)
-{
-	page &= PAGE_MASK;
-	__asm__ __volatile__("sta %%g0, [%0] %1\n\t": :
-			     "r" (page),        /* Flush TLB page.. */
-			     "i" (ASI_M_FLUSH_PROBE) : "memory");
-
-}
-
-static inline unsigned long apmmu_hwprobe(unsigned long vaddr)
-{
-	unsigned long retval;
-
-	vaddr &= PAGE_MASK;
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (retval) :
-			     "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
-
-	return retval;
-}
-
-static inline void apmmu_uncache_page(unsigned long addr)
-{
-	pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr);
-	pmd_t *pmdp;
-	pte_t *ptep;
-
-	if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
-		ptep = (pte_t *) pgdp;
-	} else {
-		pmdp = apmmu_pmd_offset(pgdp, addr);
-		if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
-			ptep = (pte_t *) pmdp;
-		} else {
-			ptep = apmmu_pte_offset(pmdp, addr);
-		}
-	}
-
-	set_pte(ptep, __pte((pte_val(*ptep) & ~APMMU_CACHE)));
-	viking_flush_tlb_page_for_cbit(addr);
-}
-
-static inline void apmmu_recache_page(unsigned long addr)
-{
-	pgd_t *pgdp = apmmu_pgd_offset(&init_mm, addr);
-	pmd_t *pmdp;
-	pte_t *ptep;
-
-	if((pgd_val(*pgdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
-		ptep = (pte_t *) pgdp;
-	} else {
-		pmdp = apmmu_pmd_offset(pgdp, addr);
-		if((pmd_val(*pmdp) & APMMU_ET_MASK) == APMMU_ET_PTE) {
-			ptep = (pte_t *) pmdp;
-		} else {
-			ptep = apmmu_pte_offset(pmdp, addr);
-		}
-	}
-	set_pte(ptep, __pte((pte_val(*ptep) | APMMU_CACHE)));
-	viking_flush_tlb_page_for_cbit(addr);
-}
-
-static inline unsigned long apmmu_getpage(void)
-{
-	unsigned long page = get_free_page(GFP_KERNEL);
-
-	return page;
-}
-
-static inline void apmmu_putpage(unsigned long page)
-{
-	free_page(page);
-}
-
-/* The easy versions. */
-#define NEW_PGD() (pgd_t *) apmmu_getpage()
-#define NEW_PMD() (pmd_t *) apmmu_getpage()
-#define NEW_PTE() (pte_t *) apmmu_getpage()
-#define FREE_PGD(chunk) apmmu_putpage((unsigned long)(chunk))
-#define FREE_PMD(chunk) apmmu_putpage((unsigned long)(chunk))
-#define FREE_PTE(chunk) apmmu_putpage((unsigned long)(chunk))
-
-static pte_t *apmmu_get_pte_fast(void)
-{
-	return (pte_t *)0;
-}
-
-static pmd_t *apmmu_get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
-
-static pgd_t *apmmu_get_pgd_fast(void)
-{
-	return (pgd_t *)0;
-}
-
-static void apmmu_free_pte_slow(pte_t *pte)
-{
-/* TBD */
-}
-
-static void apmmu_free_pmd_slow(pmd_t *pmd)
-{
-/* TBD */
-}
-
-static void apmmu_free_pgd_slow(pgd_t *pgd)
-{
-/* TBD */
-}
-
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any, and marks the page tables reserved.
- */
-static void apmmu_pte_free_kernel(pte_t *pte)
-{
-	FREE_PTE(pte);
-}
-
-static pte_t *apmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1);
-	if(apmmu_pmd_none(*pmd)) {
-		pte_t *page = NEW_PTE();
-		if(apmmu_pmd_none(*pmd)) {
-			if(page) {
-				apmmu_pmd_set(pmd, page);
-				return page + address;
-			}
-			apmmu_pmd_set(pmd, BAD_PAGETABLE);
-			return NULL;
-		}
-		FREE_PTE(page);
-	}
-	if(apmmu_pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		apmmu_pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	return (pte_t *) apmmu_pmd_page(*pmd) + address;
-}
-
-static void apmmu_pmd_free_kernel(pmd_t *pmd)
-{
-	FREE_PMD(pmd);
-}
-
-static pmd_t *apmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
-{
-	address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1);
-	if(apmmu_pgd_none(*pgd)) {
-		pmd_t *page;
-		page = NEW_PMD();
-		if(apmmu_pgd_none(*pgd)) {
-			if(page) {
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
-			return NULL;
-		}
-		FREE_PMD(page);
-	}
-	if(apmmu_pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
-		return NULL;
-	}
-	return (pmd_t *) pgd_page(*pgd) + address;
-}
-
-static void apmmu_pte_free(pte_t *pte)
-{
-	FREE_PTE(pte);
-}
-
-static pte_t *apmmu_pte_alloc(pmd_t * pmd, unsigned long address)
-{
-	address = (address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1);
-	if(apmmu_pmd_none(*pmd)) {
-		pte_t *page = NEW_PTE();
-		if(apmmu_pmd_none(*pmd)) {
-			if(page) {
-				apmmu_pmd_set(pmd, page);
-				return page + address;
-			}
-			apmmu_pmd_set(pmd, BAD_PAGETABLE);
-			return NULL;
-		}
-		FREE_PTE(page);
-	}
-	if(apmmu_pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		apmmu_pmd_set(pmd, BAD_PAGETABLE);
-		return NULL;
-	}
-	return ((pte_t *) apmmu_pmd_page(*pmd)) + address;
-}
-
-/* Real three-level page tables on APMMU. */
-static void apmmu_pmd_free(pmd_t * pmd)
-{
-	FREE_PMD(pmd);
-}
-
-static pmd_t *apmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
-{
-	address = (address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1);
-	if(apmmu_pgd_none(*pgd)) {
-		pmd_t *page = NEW_PMD();
-		if(apmmu_pgd_none(*pgd)) {
-			if(page) {
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
-			return NULL;
-		}
-		FREE_PMD(page);
-	}
-	if(apmmu_pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, (pmd_t *) BAD_PAGETABLE);
-		return NULL;
-	}
-	return (pmd_t *) apmmu_pgd_page(*pgd) + address;
-}
-
-static void apmmu_pgd_free(pgd_t *pgd)
-{
-	FREE_PGD(pgd);
-}
-
-static pgd_t *apmmu_pgd_alloc(void)
-{
-	return NEW_PGD();
-}
-
-static void apmmu_pgd_flush(pgd_t *pgdp)
-{
-}
-
-static void apmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval)
-{
-	apmmu_set_entry(ptep, pte_val(pteval));
-}
-
-static void apmmu_quick_kernel_fault(unsigned long address)
-{
-	printk("Kernel faults at addr=0x%08lx\n", address);
-	printk("PTE=%08lx\n", apmmu_hwprobe((address & PAGE_MASK)));
-	die_if_kernel("APMMU bolixed...", current->thread.kregs);
-}
-
-static inline void alloc_context(struct task_struct *tsk)
-{
-	struct mm_struct *mm = tsk->mm;
-	struct ctx_list *ctxp;
-
-	if (tsk->taskid >= MPP_TASK_BASE) {
-		mm->context = MPP_CONTEXT_BASE + (tsk->taskid - MPP_TASK_BASE);
-		return;
-	}
-
-	ctxp = ctx_free.next;
-	if(ctxp != &ctx_free) {
-		remove_from_ctx_list(ctxp);
-		add_to_used_ctxlist(ctxp);
-		mm->context = ctxp->ctx_number;
-		ctxp->ctx_mm = mm;
-		return;
-	}
-	ctxp = ctx_used.next;
-	if(ctxp->ctx_mm == current->mm)
-		ctxp = ctxp->next;
-	if(ctxp == &ctx_used)
-		panic("out of mmu contexts");
-	flush_cache_mm(ctxp->ctx_mm);
-	flush_tlb_mm(ctxp->ctx_mm);
-	remove_from_ctx_list(ctxp);
-	add_to_used_ctxlist(ctxp);
-	ctxp->ctx_mm->context = NO_CONTEXT;
-	ctxp->ctx_mm = mm;
-	mm->context = ctxp->ctx_number;
-}
-
-static inline void free_context(int context)
-{
-	struct ctx_list *ctx_old;
-
-	if (context >= MPP_CONTEXT_BASE)
-		return; /* nothing to do! */
-	
-	ctx_old = ctx_list_pool + context;
-	remove_from_ctx_list(ctx_old);
-	add_to_free_ctxlist(ctx_old);
-}
-
-
-static void apmmu_switch_to_context(struct task_struct *tsk)
-{
-	if(tsk->mm->context == NO_CONTEXT) {
-		alloc_context(tsk);
-		flush_cache_mm(current->mm);
-		apmmu_ctxd_set(&apmmu_context_table[tsk->mm->context], tsk->mm->pgd);
-		flush_tlb_mm(current->mm);
-	}
-	apmmu_set_context(tsk->mm->context);
-}
-
-static char *apmmu_lockarea(char *vaddr, unsigned long len)
-{
-	return vaddr;
-}
-
-static void apmmu_unlockarea(char *vaddr, unsigned long len)
-{
-}
-
-struct task_struct *apmmu_alloc_task_struct(void)
-{
-	return (struct task_struct *) kmalloc(sizeof(struct task_struct), GFP_KERNEL);
-}
-
-static void apmmu_free_task_struct(struct task_struct *tsk)
-{
-	kfree(tsk);
-}
-
-static void apmmu_null_func(void)
-{
-}
-
-static inline void mc_tlb_flush_all(void)
-{
-	unsigned long long *tlb4k;
-	int i;
-	
-	tlb4k = (unsigned long long *)MC_MMU_TLB4K;
-	for (i = MC_MMU_TLB4K_SIZE/4; i > 0; --i) {
-		tlb4k[0] = 0;
-		tlb4k[1] = 0;
-		tlb4k[2] = 0;
-		tlb4k[3] = 0;
-		tlb4k += 4;
-	}
-}
-
-static inline void mc_tlb_flush_page(unsigned vaddr,int ctx) 
-{
-	if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) {
-		*(((unsigned long long *)MC_MMU_TLB4K) + ((vaddr>>12)&0xFF)) = 0;
-	}
-}
-
-static inline void mc_tlb_flush_ctx(int ctx) 
-{
-	unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K;
-	if (ctx == SYSTEM_CONTEXT || MPP_IS_PAR_CTX(ctx)) {
-		int i;
-		for (i=0; i<MC_MMU_TLB4K_SIZE;i++)
-			if (((tlb4k[i] >> 5) & 0xFFF) == ctx) tlb4k[i] = 0;
-	}
-}
-
-static inline void mc_tlb_flush_region(unsigned start,int ctx)
-{
-	mc_tlb_flush_ctx(ctx);
-}
-
-static inline void mc_tlb_flush_segment(unsigned start,int ctx)
-{
-	mc_tlb_flush_ctx(ctx);
-}
-
-static void viking_flush_tlb_all(void)
-{
-	module_stats.invall++;
-	flush_user_windows(); 	
-	apmmu_flush_whole_tlb();
-	mc_tlb_flush_all();
-}
-
-static void viking_flush_tlb_mm(struct mm_struct *mm)
-{
-	int octx;
-
-	module_stats.invmm++;
-
-	if(mm->context != NO_CONTEXT) {
-		flush_user_windows();
-		octx = apmmu_get_context();
-		if (octx != mm->context) 
-			apmmu_set_context(mm->context);
-		apmmu_flush_tlb_ctx();
-		mc_tlb_flush_ctx(mm->context);
-		if (octx != mm->context)
-			apmmu_set_context(octx);
-	}
-}
-
-static void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-	int octx;
-
-	module_stats.invrnge++;
-
-	if(mm->context != NO_CONTEXT) {
-		flush_user_windows();
-		octx = apmmu_get_context();
-		if (octx != mm->context)
-			apmmu_set_context(mm->context);
-		if((end - start) < APMMU_PMD_SIZE) {
-			start &= PAGE_MASK;
-			while(start < end) {
-				apmmu_flush_tlb_page(start);
-				mc_tlb_flush_page(start,mm->context);
-				start += PAGE_SIZE;
-			}
-		} else if((end - start) < APMMU_PGDIR_SIZE) {
-			start &= APMMU_PMD_MASK;
-			while(start < end) {
-				apmmu_flush_tlb_segment(start);
-				mc_tlb_flush_segment(start,mm->context);
-				start += APMMU_PMD_SIZE;
-			}
-		} else {
-			start &= APMMU_PGDIR_MASK;
-			while(start < end) {
-				apmmu_flush_tlb_region(start);
-				mc_tlb_flush_region(start,mm->context);
-				start += APMMU_PGDIR_SIZE;
-			}
-		}
-		if (octx != mm->context)
-			apmmu_set_context(octx);
-	}
-}
-
-static void viking_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
-	int octx;
-	struct mm_struct *mm = vma->vm_mm;
-
-	module_stats.invpg++;
-	if(mm->context != NO_CONTEXT) {
-		flush_user_windows();
-		octx = apmmu_get_context();
-		if (octx != mm->context)
-			apmmu_set_context(mm->context);
-		apmmu_flush_tlb_page(page);
-		mc_tlb_flush_page(page,mm->context);
-		if (octx != mm->context)
-			apmmu_set_context(octx);
-	}
-}
-
-static void viking_flush_tlb_page_for_cbit(unsigned long page)
-{
-	apmmu_flush_tlb_page(page);
-	mc_tlb_flush_page(page,apmmu_get_context());
-}
-
-/* Some dirty hacks to abstract away the painful boot up init. */
-static inline unsigned long apmmu_early_paddr(unsigned long vaddr)
-{
-	return (vaddr - KERNBASE);
-}
-
-static inline void apmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp)
-{
-	set_pte((pte_t *)pgdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) pmdp) >> 4))));
-}
-
-static inline void apmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep)
-{
-	set_pte((pte_t *)pmdp, __pte((APMMU_ET_PTD | (apmmu_early_paddr((unsigned long) ptep) >> 4))));
-}
-
-static inline unsigned long apmmu_early_pgd_page(pgd_t pgd)
-{
-	return ((pgd_val(pgd) & APMMU_PTD_PMASK) << 4) + KERNBASE;
-}
-
-static inline unsigned long apmmu_early_pmd_page(pmd_t pmd)
-{
-	return ((pmd_val(pmd) & APMMU_PTD_PMASK) << 4) + KERNBASE;
-}
-
-static inline pmd_t *apmmu_early_pmd_offset(pgd_t *dir, unsigned long address)
-{
-	return (pmd_t *) apmmu_early_pgd_page(*dir) + ((address >> APMMU_PMD_SHIFT) & (APMMU_PTRS_PER_PMD - 1));
-}
-
-static inline pte_t *apmmu_early_pte_offset(pmd_t *dir, unsigned long address)
-{
-	return (pte_t *) apmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (APMMU_PTRS_PER_PTE - 1));
-}
-
-static inline void __init apmmu_allocate_ptable_skeleton(unsigned long start, unsigned long end)
-{
-	pgd_t *pgdp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-
-	while(start < end) {
-		pgdp = apmmu_pgd_offset(&init_mm, start);
-		if(apmmu_pgd_none(*pgdp)) {
-			pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
-			apmmu_early_pgd_set(pgdp, pmdp);
-		}
-		pmdp = apmmu_early_pmd_offset(pgdp, start);
-		if(apmmu_pmd_none(*pmdp)) {
-			ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE);
-			apmmu_early_pmd_set(pmdp, ptep);
-		}
-		start = (start + APMMU_PMD_SIZE) & APMMU_PMD_MASK;
-	}
-}
-
-
-static void __init make_page(unsigned virt_page, unsigned phys_page, unsigned prot)
-{
-	pgd_t *pgdp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-	unsigned start = virt_page<<12;
-
-	pgdp = apmmu_pgd_offset(&init_mm, start);
-	if(apmmu_pgd_none(*pgdp)) {
-		pmdp = sparc_init_alloc(&mempool, APMMU_PMD_TABLE_SIZE);
-		apmmu_early_pgd_set(pgdp, pmdp);
-	}
-	pmdp = apmmu_early_pmd_offset(pgdp, start);
-	if(apmmu_pmd_none(*pmdp)) {
-		ptep = sparc_init_alloc(&mempool, APMMU_PTE_TABLE_SIZE);
-		apmmu_early_pmd_set(pmdp, ptep);
-	}
-	ptep = apmmu_early_pte_offset(pmdp, start);
-	*ptep = __pte((phys_page<<8) | prot);
-}
-
-
-static void __init make_large_page(unsigned virt_page, unsigned phys_page, unsigned prot)
-{
-	pgd_t *pgdp;
-	unsigned start = virt_page<<12;
-
-	pgdp = apmmu_pgd_offset(&init_mm, start);
-	*pgdp = __pgd((phys_page<<8) | prot);
-}
-
-
-static void __init ap_setup_mappings(void)
-{
-	unsigned Srwe = APMMU_PRIV | APMMU_VALID;
-	unsigned SrweUr = 0x14 | APMMU_VALID; /* weird! */
-
-	/* LBus */
-	make_large_page(0xfb000,0x9fb000,Srwe);
-	make_large_page(0xff000,0x9ff000,SrweUr); 
-	make_large_page(0xfc000,0x911000,Srwe);
-
-	/* MC Register */
-	make_page(0xfa000,0xb00000,SrweUr);
-	make_page(0xfa001,0xb00001,Srwe);
-	make_page(0xfa002,0xb00002,Srwe);
-	make_page(0xfa003,0xb00003,Srwe);
-	make_page(0xfa004,0xb00004,Srwe);
-	make_page(0xfa005,0xb00005,Srwe);
-	make_page(0xfa006,0xb00006,Srwe);
-	make_page(0xfa007,0xb00007,Srwe);
-  
-	/* MSC+ Register */
-	make_page(0xfa008,0xc00000,SrweUr);
-	make_page(0xfa009,0xc00001,Srwe);
-	make_page(0xfa00a,0xc00002,Srwe);
-	make_page(0xfa00b,0xc00003,Srwe);
-	make_page(0xfa00c,0xc00004,Srwe);
-	make_page(0xfa00d,0xc00005,Srwe); /* RBMPR 0 */
-	make_page(0xfa00e,0xc00006,Srwe);  /* RBMPR 1 */
-	make_page(0xfa00f,0xc00007,Srwe);  /* RBMPR 2 */
-
-	/* user queues */
-	make_page(MSC_PUT_QUEUE>>PAGE_SHIFT,  0xa00000,Srwe); 
-	make_page(MSC_GET_QUEUE>>PAGE_SHIFT,  0xa00001,Srwe); 
-	make_page(MSC_SEND_QUEUE>>PAGE_SHIFT, 0xa00040,Srwe); 
-	make_page(MSC_XY_QUEUE>>PAGE_SHIFT,   0xa00640,Srwe); 
-	make_page(MSC_X_QUEUE>>PAGE_SHIFT,    0xa00240,Srwe); 
-	make_page(MSC_Y_QUEUE>>PAGE_SHIFT,    0xa00440,Srwe); 
-	make_page(MSC_XYG_QUEUE>>PAGE_SHIFT,  0xa00600,Srwe); 
-	make_page(MSC_XG_QUEUE>>PAGE_SHIFT,   0xa00200,Srwe); 
-	make_page(MSC_YG_QUEUE>>PAGE_SHIFT,   0xa00400,Srwe); 
-	make_page(MSC_CSI_QUEUE>>PAGE_SHIFT,  0xa02004,Srwe); 
-	make_page(MSC_FOP_QUEUE>>PAGE_SHIFT,  0xa02005,Srwe); 
-	
-	/* system queues */
-	make_page(MSC_PUT_QUEUE_S>>PAGE_SHIFT,  0xa02000,Srwe); /* system put */
-	make_page(MSC_CPUT_QUEUE_S>>PAGE_SHIFT, 0xa02020,Srwe); /* system creg put */
-	make_page(MSC_GET_QUEUE_S>>PAGE_SHIFT,  0xa02001,Srwe); /* system get */
-	make_page(MSC_CGET_QUEUE_S>>PAGE_SHIFT, 0xa02021,Srwe); /* system creg get */
-	make_page(MSC_SEND_QUEUE_S>>PAGE_SHIFT, 0xa02040,Srwe); /* system send */
-	make_page(MSC_BSEND_QUEUE_S>>PAGE_SHIFT,0xa02640,Srwe); /* system send broad */
-	make_page(MSC_XYG_QUEUE_S>>PAGE_SHIFT,  0xa02600,Srwe); /* system put broad */  
-	make_page(MSC_CXYG_QUEUE_S>>PAGE_SHIFT, 0xa02620,Srwe); /* system put broad */  
-	
-	/* Direct queue access entries for refilling the MSC send queue */
-	make_page(MSC_SYSTEM_DIRECT>>PAGE_SHIFT, 0xa08000,Srwe);
-	make_page(MSC_USER_DIRECT>>PAGE_SHIFT, 0xa08001,Srwe);
-	make_page(MSC_REMOTE_DIRECT>>PAGE_SHIFT, 0xa08002,Srwe);
-	make_page(MSC_REPLY_DIRECT>>PAGE_SHIFT, 0xa08003,Srwe);
-	make_page(MSC_REMREPLY_DIRECT>>PAGE_SHIFT, 0xa08004,Srwe);
-
-	/* As above with end-bit set */
-	make_page(MSC_SYSTEM_DIRECT_END>>PAGE_SHIFT, 0xa0c000,Srwe);
-	make_page(MSC_USER_DIRECT_END>>PAGE_SHIFT, 0xa0c001,Srwe);
-	make_page(MSC_REMOTE_DIRECT_END>>PAGE_SHIFT, 0xa0c002,Srwe);
-	make_page(MSC_REPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c003,Srwe);
-	make_page(MSC_REMREPLY_DIRECT_END>>PAGE_SHIFT, 0xa0c004,Srwe);
-}
-
-static void __init map_kernel(void)
-{
-	int phys;
-
-	/* the AP+ only ever has one bank of memory starting at address 0 */
-	ap_mem_size = sp_banks[0].num_bytes;
-	for (phys=0; phys < sp_banks[0].num_bytes; phys += APMMU_PGDIR_SIZE)
-		make_large_page((KERNBASE+phys)>>12,
-				(phys>>12),
-				APMMU_CACHE|APMMU_PRIV|APMMU_VALID);
-	init_mm.mmap->vm_start = PAGE_OFFSET;
-}
-
-extern unsigned long free_area_init(unsigned long, unsigned long);
-extern unsigned long sparc_context_init(unsigned long, int);
-
-extern int physmem_mapped_contig;
-extern int linux_num_cpus;
-
-unsigned long __init apmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
-	int i;
-
-	physmem_mapped_contig = 1;   /* for init.c:taint_real_pages()   */
-
-	num_contexts = AP_NUM_CONTEXTS;
-	mempool = PAGE_ALIGN(start_mem);
-	memset(swapper_pg_dir, 0, PAGE_SIZE);
-
-	apmmu_allocate_ptable_skeleton(KERNBASE, end_mem);
-	mempool = PAGE_ALIGN(mempool);
-	map_kernel();
-	ap_setup_mappings();
-
-	/* the MSC wants this aligned on a 16k boundary */
-	apmmu_context_table = 
-	  sparc_init_alloc(&mempool, 
-			   num_contexts*sizeof(ctxd_t)<0x4000?
-			   0x4000:
-			   num_contexts*sizeof(ctxd_t));
-	apmmu_ctx_table_phys = (ctxd_t *) apmmu_v2p((unsigned long) apmmu_context_table);
-	for(i = 0; i < num_contexts; i++)
-		apmmu_ctxd_set(&apmmu_context_table[i], swapper_pg_dir);
-
-	start_mem = PAGE_ALIGN(mempool);
-
-	flush_cache_all();
-	apmmu_set_ctable_ptr((unsigned long) apmmu_ctx_table_phys);
-	flush_tlb_all();
-	poke_viking();
-
-	/* on the AP we don't put the top few contexts into the free
-	   context list as these are reserved for parallel tasks */
-	start_mem = sparc_context_init(start_mem, MPP_CONTEXT_BASE);
-	start_mem = free_area_init(start_mem, end_mem);
-
-	return PAGE_ALIGN(start_mem);
-}
-
-static int apmmu_mmu_info(char *buf)
-{
-	return sprintf(buf, 
-		"MMU type\t: %s\n"
-		"invall\t\t: %d\n"
-		"invmm\t\t: %d\n"
-		"invrnge\t\t: %d\n"
-		"invpg\t\t: %d\n"
-		"contexts\t: %d\n"
-		, apmmu_name,
-		module_stats.invall,
-		module_stats.invmm,
-		module_stats.invrnge,
-		module_stats.invpg,
-		num_contexts
-		);
-}
-
-static void apmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte)
-{
-}
-
-static void __init poke_viking(void)
-{
-	unsigned long mreg = apmmu_get_mmureg();
-
-	mreg |= VIKING_SPENABLE;
-	mreg |= (VIKING_ICENABLE | VIKING_DCENABLE);
-	mreg &= ~VIKING_ACENABLE;
-	mreg &= ~VIKING_SBENABLE;
-	mreg |= VIKING_TCENABLE;
-	apmmu_set_mmureg(mreg);
-}
-
-static void __init init_viking(void)
-{
-	apmmu_name = "TI Viking/AP1000";
-
-	BTFIXUPSET_CALL(flush_cache_all, apmmu_null_func, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(flush_cache_mm, apmmu_null_func, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(flush_cache_page, apmmu_null_func, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(flush_cache_range, apmmu_null_func, BTFIXUPCALL_NOP);
-
-	BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(flush_page_to_ram, apmmu_null_func, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(flush_sig_insns, apmmu_null_func, BTFIXUPCALL_NOP);
-}
-
-
-extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme,
-	tsetup_mmu_patchme, rtrap_mmu_patchme;
-
-extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk,
-	tsetup_srmmu_stackchk, srmmu_rett_stackchk;
-
-extern unsigned long srmmu_fault;
-
-#define PATCH_BRANCH(insn, dest) do { \
-		iaddr = &(insn); \
-		daddr = &(dest); \
-		*iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
-	} while(0);
-
-static void __init patch_window_trap_handlers(void)
-{
-	unsigned long *iaddr, *daddr;
-	
-	PATCH_BRANCH(spwin_mmu_patchme, spwin_srmmu_stackchk);
-	PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk);
-	PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk);
-	PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk);
-	PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault);
-	PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault);
-	PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault);
-}
-
-/* Load up routines and constants for apmmu */
-void __init ld_mmu_apmmu(void)
-{
-	/* First the constants */
-	BTFIXUPSET_SIMM13(pmd_shift, APMMU_PMD_SHIFT);
-	BTFIXUPSET_SETHI(pmd_size, APMMU_PMD_SIZE);
-	BTFIXUPSET_SETHI(pmd_mask, APMMU_PMD_MASK);
-	BTFIXUPSET_SIMM13(pgdir_shift, APMMU_PGDIR_SHIFT);
-	BTFIXUPSET_SETHI(pgdir_size, APMMU_PGDIR_SIZE);
-	BTFIXUPSET_SETHI(pgdir_mask, APMMU_PGDIR_MASK);
-
-	BTFIXUPSET_SIMM13(ptrs_per_pte, APMMU_PTRS_PER_PTE);
-	BTFIXUPSET_SIMM13(ptrs_per_pmd, APMMU_PTRS_PER_PMD);
-	BTFIXUPSET_SIMM13(ptrs_per_pgd, APMMU_PTRS_PER_PGD);
-
-	BTFIXUPSET_INT(page_none, pgprot_val(APMMU_PAGE_NONE));
-	BTFIXUPSET_INT(page_shared, pgprot_val(APMMU_PAGE_SHARED));
-	BTFIXUPSET_INT(page_copy, pgprot_val(APMMU_PAGE_COPY));
-	BTFIXUPSET_INT(page_readonly, pgprot_val(APMMU_PAGE_RDONLY));
-	BTFIXUPSET_INT(page_kernel, pgprot_val(APMMU_PAGE_KERNEL));
-	pg_iobits = APMMU_VALID | APMMU_WRITE | APMMU_REF;
-	    
-	/* Functions */
-	BTFIXUPSET_CALL(get_pte_fast, apmmu_get_pte_fast, BTFIXUPCALL_RETINT(0));
-	BTFIXUPSET_CALL(get_pmd_fast, apmmu_get_pmd_fast, BTFIXUPCALL_RETINT(0));
-	BTFIXUPSET_CALL(get_pgd_fast, apmmu_get_pgd_fast, BTFIXUPCALL_RETINT(0));
-	BTFIXUPSET_CALL(free_pte_slow, apmmu_free_pte_slow, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(free_pmd_slow, apmmu_free_pmd_slow, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(free_pgd_slow, apmmu_free_pgd_slow, BTFIXUPCALL_NOP);
-
-	BTFIXUPSET_CALL(set_pte, apmmu_set_pte_cacheable, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(switch_to_context, apmmu_switch_to_context, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(pte_page, apmmu_pte_page, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_page, apmmu_pmd_page, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_page, apmmu_pgd_page, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(sparc_update_rootmmu_dir, apmmu_update_rootmmu_dir, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_SETHI(none_mask, 0xF0000000);
-
-	BTFIXUPSET_CALL(pte_present, apmmu_pte_present, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_clear, apmmu_pte_clear, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(pmd_bad, apmmu_pmd_bad, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_present, apmmu_pmd_present, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_clear, apmmu_pmd_clear, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(pgd_none, apmmu_pgd_none, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_bad, apmmu_pgd_bad, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_present, apmmu_pgd_present, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_clear, apmmu_pgd_clear, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(mk_pte, apmmu_mk_pte, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mk_pte_phys, apmmu_mk_pte_phys, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mk_pte_io, apmmu_mk_pte_io, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_set, apmmu_pgd_set, BTFIXUPCALL_NORM);
-	
-	BTFIXUPSET_INT(pte_modify_mask, APMMU_CHG_MASK);
-	BTFIXUPSET_CALL(pgd_offset, apmmu_pgd_offset, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_offset, apmmu_pmd_offset, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_offset, apmmu_pte_offset, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_free_kernel, apmmu_pte_free_kernel, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_free_kernel, apmmu_pmd_free_kernel, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_alloc_kernel, apmmu_pte_alloc_kernel, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_alloc_kernel, apmmu_pmd_alloc_kernel, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_free, apmmu_pte_free, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_alloc, apmmu_pte_alloc, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_free, apmmu_pmd_free, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pmd_alloc, apmmu_pmd_alloc, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_free, apmmu_pgd_free, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_alloc, apmmu_pgd_alloc, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pgd_flush, apmmu_pgd_flush, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_HALF(pte_writei, APMMU_WRITE);
-	BTFIXUPSET_HALF(pte_dirtyi, APMMU_DIRTY);
-	BTFIXUPSET_HALF(pte_youngi, APMMU_REF);
-	BTFIXUPSET_HALF(pte_wrprotecti, APMMU_WRITE);
-	BTFIXUPSET_HALF(pte_mkcleani, APMMU_DIRTY);
-	BTFIXUPSET_HALF(pte_mkoldi, APMMU_REF);
-	BTFIXUPSET_CALL(pte_mkwrite, apmmu_pte_mkwrite, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_mkdirty, apmmu_pte_mkdirty, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(pte_mkyoung, apmmu_pte_mkyoung, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(update_mmu_cache, apmmu_update_mmu_cache, BTFIXUPCALL_NOP);
-
-	BTFIXUPSET_CALL(mmu_lockarea, apmmu_lockarea, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mmu_unlockarea, apmmu_unlockarea, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(mmu_get_scsi_one, apmmu_null_func, BTFIXUPCALL_RETO0);
-	BTFIXUPSET_CALL(mmu_get_scsi_sgl, apmmu_null_func, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(mmu_release_scsi_one, apmmu_null_func, BTFIXUPCALL_NOP);
-	BTFIXUPSET_CALL(mmu_release_scsi_sgl, apmmu_null_func, BTFIXUPCALL_NOP);
-
-	BTFIXUPSET_CALL(mmu_info, apmmu_mmu_info, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mmu_v2p, apmmu_v2p, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(mmu_p2v, apmmu_p2v, BTFIXUPCALL_NORM);
-
-	/* Task struct and kernel stack allocating/freeing. */
-	BTFIXUPSET_CALL(alloc_task_struct, apmmu_alloc_task_struct, BTFIXUPCALL_NORM);
-	BTFIXUPSET_CALL(free_task_struct, apmmu_free_task_struct, BTFIXUPCALL_NORM);
-
-	BTFIXUPSET_CALL(quick_kernel_fault, apmmu_quick_kernel_fault, BTFIXUPCALL_NORM);
-
-	init_viking();
-	patch_window_trap_handlers();
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/approm.c linux/arch/sparc/ap1000/approm.c
--- v2.3.41/linux/arch/sparc/ap1000/approm.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/approm.c	Wed Dec 31 16:00:00 1969
@@ -1,148 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * fake a really simple Sun prom for the AP+
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h> 
-#include <asm/machines.h> 
-#include <asm/ap1000/apservice.h> 
-
-static struct linux_romvec ap_romvec;
-static struct idprom ap_idprom;
-
-struct property {
-	char *name;
-	char *value;
-	int length;
-};
-
-struct node {
-	int level;
-	struct property *properties;
-};
-
-struct property null_properties = { NULL, NULL, -1 };
-
-struct property root_properties[] = {
-	{"device_type", "cpu", 4},
-	{"idprom",      (char *)&ap_idprom, sizeof(ap_idprom)},
-	{"banner-name", "Fujitsu AP1000+", 16},
-	{NULL, NULL, -1}
-};
-
-struct node nodes[] = {
-	{ 0, &null_properties }, 
-	{ 0, root_properties },
-	{ -1,&null_properties }
-};
-
-
-static int no_nextnode(int node)
-{
-	if (nodes[node].level == nodes[node+1].level)
-		return node+1;
-	return -1;
-}
-
-static int no_child(int node)
-{
-	if (nodes[node].level == nodes[node+1].level-1)
-		return node+1;
-	return -1;
-}
-
-static struct property *find_property(int node,char *name)
-{
-	struct property *prop = &nodes[node].properties[0];
-	while (prop && prop->name) {
-		if (strcmp(prop->name,name) == 0) return prop;
-		prop++;
-	}
-	return NULL;
-}
-
-static int no_proplen(int node,char *name)
-{
-	struct property *prop = find_property(node,name);
-	if (prop) return prop->length;
-	return -1;
-}
-
-static int no_getprop(int node,char *name,char *value)
-{
-	struct property *prop = find_property(node,name);
-	if (prop) {
-		memcpy(value,prop->value,prop->length);
-		return 1;
-	}
-	return -1;
-}
-
-static int no_setprop(int node,char *name,char *value,int len)
-{
-	return -1;
-}
-
-static char *no_nextprop(int node,char *name)
-{
-	struct property *prop = find_property(node,name);
-	if (prop) return prop[1].name;
-	return NULL;
-}
-
-
-static struct linux_nodeops ap_nodeops = {
-	no_nextnode,
-	no_child,
-	no_proplen,
-	no_getprop,
-	no_setprop,
-	no_nextprop
-};
-
-
-	
-static unsigned char calc_idprom_cksum(struct idprom *idprom)
-{
-        unsigned char cksum, i, *ptr = (unsigned char *)idprom;
-
-        for (i = cksum = 0; i <= 0x0E; i++)
-                cksum ^= *ptr++;
-
-        return cksum;
-}
-
-static int synch_hook;
-
-
-struct linux_romvec *ap_prom_init(void)
-{
-	memset(&ap_romvec,0,sizeof(ap_romvec));
-
-	ap_romvec.pv_romvers = 42;
-	ap_romvec.pv_nodeops = &ap_nodeops;
-	ap_romvec.pv_reboot = ap_reboot;
-	ap_romvec.pv_synchook = &synch_hook;
-
-	ap_idprom.id_format = 1;
-	ap_idprom.id_sernum = mpp_cid();
-	ap_idprom.id_machtype = SM_SUN4M_OBP;
-	ap_idprom.id_cksum = calc_idprom_cksum(&ap_idprom);
-
-	return &ap_romvec;
-}
-
-
-
-
-
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/bnet.c linux/arch/sparc/ap1000/bnet.c
--- v2.3.41/linux/arch/sparc/ap1000/bnet.c	Fri Feb 20 18:28:22 1998
+++ linux/arch/sparc/ap1000/bnet.c	Wed Dec 31 16:00:00 1969
@@ -1,1205 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* routines to control the AP1000 bif interface. This is the interface
-   used to talk to the front end processor */
-
-#include <linux/sched.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <asm/irq.h>
-#include <linux/skbuff.h>
-
-#define NET_DEBUG 0
-
-#define DUMMY_MSG_LEN 100
-#define DUMMY_MSG_WAIT 30
-
-#define MAX_CELLS 128
-
-#define HAVE_BIF() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG)
-#define BIF_BUSY() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_BB)
-
-#define SNET_ARBITRATION 0
-#define TOKEN_ARBITRATION 1
-
-#define DEBUG(x) 
-
-#if TOKEN_ARBITRATION
-static int have_token = 0;
-#endif
-
-extern struct cap_init cap_init;
-
-static int interrupt_driven = 0;
-static int use_dma = 0;
-struct pt_regs *bif_pt_regs = NULL;
-enum dma_state {DMA_IDLE,DMA_INCOMING,DMA_OUTGOING};
-static enum dma_state dma_state = DMA_IDLE;
-
-static int net_started = 0;
-static int waiting_for_bif = 0;
-static int queue_length = 0;
-
-static int drop_ip_packets = 0;
-
-#define DMA_THRESHOLD 64
-
-static struct cap_request bread_req;
-
-int tnet_ip_enabled = 1;
-
-#define BIF_DATA_WAITING() (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)
-
-#define ROUND4(x)	(((x) + 3) & -4)
-
-static void bif_intr_receive(struct cap_request *req1);
-
-
-/* read some data from the bif */
-void read_bif(char *buf,int size) 
-{
-	unsigned *ibuf = (unsigned *)buf;
-	unsigned avail;
-
-	DEBUG(("|read_bif %d\n",size));
-	
-	if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2);  
-	
-	size = (size+3) >> 2;
-
-	while (size > 4) {
-		while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_RB_SHIFT) & 7))
-			;
-		if (avail & 4) {
-			ibuf[0] = BIF_IN(BIF_DATA);
-			ibuf[1] = BIF_IN(BIF_DATA);
-			ibuf[2] = BIF_IN(BIF_DATA);
-			ibuf[3] = BIF_IN(BIF_DATA);
-			size -= 4; ibuf += 4;
-			continue;
-		}
-
-		if (avail & 2) {
-			ibuf[0] = BIF_IN(BIF_DATA);
-			ibuf[1] = BIF_IN(BIF_DATA);
-			size -= 2; ibuf += 2;
-			continue;
-		}
-		*ibuf++ = BIF_IN(BIF_DATA);
-		size--;
-	}
-
-	while (size--) {
-		while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)) ;
-		*ibuf++ = BIF_IN(BIF_DATA);
-	}
-
-	DEBUG(("|read bif done\n"));
-}
-
-/* throw out some data from the bif. This is usually called when we
- don't have the resources to handle it immediately */
-void bif_toss(int size) 
-{
-	unsigned flags;
-	save_flags(flags); cli();
-
-	DEBUG(("|bif toss %d\n",size));
-
-	while (size>0) {
-		while (!BIF_DATA_WAITING());
-		BIF_IN(BIF_DATA);
-		size -= 4;
-	}    
-
-	DEBUG(("|bif toss done\n"));
-
-	restore_flags(flags);
-}
-
-
-static void bif_reset_interrupts(void)
-{
-	BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_GET_SH);
-	BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_HEADER_SH);
-}
-
-static void bif_mask_interrupts(void)
-{
-	BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_GET_SH);
-	BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_HEADER_SH);
-}
-
-static void attn_enable(void)
-{
-	BIF_OUT(BIF_INTR,AP_INTR_WENABLE << BIF_INTR_ATTN_SH);
-}
-
-static void attn_mask(void)
-{
-	BIF_OUT(BIF_INTR,(AP_INTR_MASK|AP_INTR_WENABLE) << BIF_INTR_ATTN_SH);
-}
-
-
-void ap_bif_status(void)
-{
-	static int bif_sdcsr;
-	static int bif_intr;
-	static int bif_mhocr;
-	static int bif_x0sk;
-	static int bif_xsk;
-	static int bif_xsz;
-	static int bif_y0sk;
-	static int bif_ysk;
-	static int bif_ysz;
-	static int bif_cx0sk;
-	static int bif_cxsk;
-	static int bif_cxsz;
-	static int bif_cy0sk;
-	static int bif_cysk;
-	static int bif_cysz;
-	static int bif_ttl;
-	static int bif_cttl;
-	static int bif_header;
-	
-	bif_sdcsr = BIF_IN(BIF_SDCSR);
-	bif_intr  = BIF_IN(BIF_INTR);
-	bif_mhocr = BIF_IN(BIF_MHOCR);
-	
-	bif_x0sk  = BIF_IN(BIF_X0SK);
-	bif_xsk   = BIF_IN(BIF_XSK);
-	bif_xsz   = BIF_IN(BIF_XSZ);
-	bif_y0sk  = BIF_IN(BIF_Y0SK);
-	bif_ysk   = BIF_IN(BIF_YSK);
-	bif_ysz   = BIF_IN(BIF_YSZ);
-	
-	bif_cx0sk  = BIF_IN(BIF_CX0SK);
-	bif_cxsk   = BIF_IN(BIF_CXSK);
-	bif_cxsz   = BIF_IN(BIF_CXSZ);
-	bif_cy0sk  = BIF_IN(BIF_CY0SK);
-	bif_cysk   = BIF_IN(BIF_CYSK);
-	bif_cysz   = BIF_IN(BIF_CYSZ);
-	
-	bif_ttl   = BIF_IN(BIF_TTL);
-	bif_cttl  = BIF_IN(BIF_CTTL);
-	bif_header = BIF_IN(BIF_HEADER);
-
-	printk("|\t***** BIF REG. *****\n");
-	printk("|\tBIF_SDCSR  = %08x  ", bif_sdcsr);
-	if(bif_sdcsr & BIF_SDCSR_CN) printk("|<BUS DISCONNECT>");
-	if(bif_sdcsr & BIF_SDCSR_FN) printk("|<SC/GA ENABLE>");
-	if(bif_sdcsr & BIF_SDCSR_DE) printk("|<DMA ENABLE>");
-	if(bif_sdcsr & BIF_SDCSR_DR) printk("|<GATHER>");
-	if(bif_sdcsr & BIF_SDCSR_BB) printk("|<BUS BSY>");
-	if(bif_sdcsr & BIF_SDCSR_BR) printk("|<BUS REQ>");
-	if(bif_sdcsr & BIF_SDCSR_BG) printk("|<BUS GET>");
-	if(bif_sdcsr & BIF_SDCSR_ER) printk("|<ERROR:");
-	if(bif_sdcsr & BIF_SDCSR_SP) printk("|SYNC PARITY:");
-	if(bif_sdcsr & BIF_SDCSR_LP) printk("|LBUS PARITY:");
-	if(bif_sdcsr & BIF_SDCSR_LR) printk("|READ EMPTY FIFO:");
-	if(bif_sdcsr & BIF_SDCSR_LW) printk("|WRITE FULL FIFO:");
-	if(bif_sdcsr & BIF_SDCSR_AL) printk("|READ ENDBIT:");
-	if(bif_sdcsr & BIF_SDCSR_SS) printk("|SET MASK SSTAT:");
-	if(bif_sdcsr & BIF_SDCSR_SC) printk("|CLR SSYNC ILLEGALLY:");
-	if(bif_sdcsr & BIF_SDCSR_SY) printk("|REQ SSYNC ILLEGALLY:");
-	if(bif_sdcsr & BIF_SDCSR_FS) printk("|SET MASK FSTAT:");
-	if(bif_sdcsr & BIF_SDCSR_FC) printk("|CLR FSYNC ILLEGALLY:");
-	if(bif_sdcsr & BIF_SDCSR_FY) printk("|REQ FSYNC ILLEGALLY:");
-	if(bif_sdcsr & BIF_SDCSR_CP) printk("|BNET PARITY:");
-	if(bif_sdcsr & BIF_SDCSR_FP) printk("|FE NOT SET WHEN SC/GA:");
-	if(bif_sdcsr & BIF_SDCSR_PS) printk("|RECV PACKET ILLEGALLY:");
-	if(bif_sdcsr & BIF_SDCSR_RA) printk("|CHANGE FE ILLEGALLY:");
-	if(bif_sdcsr & BIF_SDCSR_PA) printk("|SEND/RECV ILLEGALLY:");
-	if(bif_sdcsr & BIF_SDCSR_DL) printk("|DATA LOST:");
-	if(bif_sdcsr & BIF_SDCSR_ER) printk("|>");
-	if(bif_sdcsr & BIF_SDCSR_PE) printk("|<SYNC PARITY ENABLE>");
-	printk("|\n");
-	printk("|\tBIF_INTR   = %08x\n", bif_intr);
-	printk("|\tBIF_MHOCR  = %08x\n", bif_mhocr);
-
-	printk("|\tBIF_X0SK   = %08x\n", bif_x0sk);
-	printk("|\tBIF_XSK    = %08x\n", bif_xsk);
-	printk("|\tBIF_XSZ    = %08x\n", bif_xsz);
-	printk("|\tBIF_Y0SK   = %08x\n", bif_y0sk);
-	printk("|\tBIF_YSK    = %08x\n", bif_ysk);
-	printk("|\tBIF_YSZ    = %08x\n", bif_ysz);
-	printk("|\tBIF_CX0SK  = %08x\n", bif_cx0sk);
-	printk("|\tBIF_CXSK   = %08x\n", bif_cxsk);
-	printk("|\tBIF_CXSZ   = %08x\n", bif_cxsz);
-	printk("|\tBIF_CY0SK  = %08x\n", bif_cy0sk);
-	printk("|\tBIF_CYSK   = %08x\n", bif_cysk);
-	printk("|\tBIF_CYSZ   = %08x\n", bif_cysz);
-
-	printk("|\tBIF_TTL    = %08x\n", bif_ttl);
-	printk("|\tBIF_CTTL   = %08x\n", bif_cttl);
-	printk("|\tBIF_HEADER = %08x\n", bif_header);
-}
-
-
-void bif_led_status(void)
-{
-#if 1
-	static int i = 0;
-	unsigned char res = 0;
-
-	switch (i) {
-	case 0: 
-	case 2: 
-		res = 0xff;
-		break;
-	case 1: 
-	case 3: 
-		res = 0;
-		break;
-	default:
-		res = 0xFF & (BIF_IN(BIF_SDCSR) >> (((i-4)/4)*8));
-	}
-	i = (i+1) % 20;
-
-	ap_led(res);
-#endif
-}
-
-static void get_bif(void)
-{
-	if (HAVE_BIF())
-		return;
-
-	drop_ip_packets = 1;
-
-	DEBUG(("|get_bif started\n"));
-
-	if (dma_state != DMA_IDLE) 
-		ap_dma_wait(DMA_CH2);  
-
-#if SNET_ARBITRATION
-	/* wait till the host doesn't want the BIF anymore, tossing
-	   any data that arrives */
-	while (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) 
-		if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)
-			bif_intr_receive(NULL);
-	waiting_for_bif = 0;
-#endif
-
-#if TOKEN_ARBITRATION
-	BIF_OUT(FSTT_CLR,HOST_STATUS_BIT);
-#endif
-
-	/* request the BIF */
-	BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR);
-
-	/* loop waiting for us to get the BIF, tossing any data */
-	while (!HAVE_BIF())
-		if (BIF_IN(BIF_SDCSR) & BIF_SDCSR_RB)
-			bif_intr_receive(NULL);
-
-	bif_reset_interrupts();
-	if (!interrupt_driven)
-		bif_mask_interrupts();
-
-	drop_ip_packets = 0;
-
-#if TOKEN_ARBITRATION
-	BIF_OUT(FSTT_SET,HOST_STATUS_BIT);
-#endif
-
-	DEBUG(("|get_bif done\n"));
-}
-
-
-/* write a message to the front end over the Bnet. This can be in
-   multiple parts, as long as the first part sets "start" and the last
-   part sets "end". The bus will be grabbed while this is going on 
-   */
-static void write_bif(char *buf,int size,int start,int end)
-{
-	unsigned *ibuf;
-	unsigned avail;
-
-	DEBUG(("|write_bif %d %d %d\n",size,start,end));
-
-	if (start) {
-		/* a dma op may be in progress */
-		if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2);
-	}
-
-	size = (size+3) >> 2;
-	ibuf = (unsigned *)buf;
-	if (end) size--;
-
-	while (size > 4) {
-		while (!(avail=(BIF_IN(BIF_SDCSR) >> BIF_SDCSR_TB_SHIFT) & 7))
-			;
-		if (avail & 4) {
-			BIF_OUT(BIF_DATA,ibuf[0]);
-			BIF_OUT(BIF_DATA,ibuf[1]);
-			BIF_OUT(BIF_DATA,ibuf[2]);
-			BIF_OUT(BIF_DATA,ibuf[3]);
-			size -= 4; ibuf += 4;
-			continue;
-		}
-
-		if (avail & 2) {
-			BIF_OUT(BIF_DATA,ibuf[0]);
-			BIF_OUT(BIF_DATA,ibuf[1]);
-			size -= 2; ibuf += 2;
-			continue;
-		}
-		BIF_OUT(BIF_DATA,ibuf[0]);
-		ibuf++; size--;
-	}
-
-	while (size--) {
-		while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ;
-		BIF_OUT(BIF_DATA,ibuf[0]);
-		ibuf++;
-	}
-
-	if (end) {
-		while (!(BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB)) ;
-		BIF_OUT(BIF_EDATA,*ibuf);
-	}
-
-	DEBUG(("|write bif done\n"));
-}
-
-#if TOKEN_ARBITRATION
-static void forward_token(void)
-{
-	struct cap_request req;
-	req.cid = mpp_cid();
-	req.type = REQ_BIF_TOKEN;
-	req.size = sizeof(req);
-	if (req.cid == cap_init.numcells - 1)
-		req.header = MAKE_HEADER(HOST_CID);
-	else
-		req.header = MAKE_HEADER(req.cid + 1);
-	
-	write_bif((char *)&req,sizeof(req),1,1);
-	have_token = 0;
-}
-#endif
-
-static void release_bif(void)
-{
-	static int dummy[DUMMY_MSG_LEN];
-
-	waiting_for_bif = 0;
-
-#if SNET_ARBITRATION
-	/* mask the attention interrupt */
-	attn_mask();
-#endif
-
-	/* maybe we don't have it?? */
-	if (!HAVE_BIF())
-		return;
-
-	DEBUG(("|release bif started\n"));
-
-	if (dma_state != DMA_IDLE) ap_dma_wait(DMA_CH2);  
-
-#if TOKEN_ARBITRATION
-	if (have_token) 
-		forward_token();	
-#endif
-
-#if 1
-	/* send a dummy message to ensure FIFO flushing
-	   (suggestion from woods to overcome bif release
-	   hardware bug) */
-	dummy[0] = 0xEEEE4000;
-	write_bif((char *)dummy,DUMMY_MSG_LEN,1,1);
-#endif
-	/* wait till the send FIFO is completely empty */
-	while (!((BIF_IN(BIF_SDCSR) & BIF_SDCSR_TB) == BIF_SDCSR_TB)) ;   
-
-	/* wait another few us */
-	udelay(DUMMY_MSG_WAIT);
-
-	/* send release-data */
-	BIF_OUT(BIF_DATA,BIF_HEADER_RS);
-	
-	/* wait until we don't have the bus */
-	while (HAVE_BIF()) ;
-
-	DEBUG(("|release bif done\n"));
-}
-
-
-/* wait for a particular request type - throwing away anything else! */
-void ap_wait_request(struct cap_request *req,int type)
-{
-	drop_ip_packets = 1;
-	do {
-		while (!BIF_DATA_WAITING())
-			if (HAVE_BIF()) release_bif();
-		read_bif((char *)req,sizeof(*req));		
-		if (req->type != type) {
-			bif_intr_receive(req);
-		}
-	} while (req->type != type);
-	drop_ip_packets = 0;
-}
-
-
-void write_bif_polled(char *buf1,int len1,char *buf2,int len2)
-{
-	unsigned flags;
-	save_flags(flags); cli();
-
-	get_bif();
-	write_bif(buf1,len1,1,(buf2&&len2)?0:1);
-	if (buf2 && len2)
-		write_bif(buf2,len2,0,1);
-	release_bif();
-	restore_flags(flags);
-}
-
-static void want_bif(void)
-{
-	unsigned flags;
-
-	save_flags(flags); cli();
-
-	/* maybe we've already got it */
-	if (HAVE_BIF()) {
-		waiting_for_bif = 0;
-		restore_flags(flags);
-		return;
-	}
-
-#if SNET_ARBITRATION	
-	if (interrupt_driven)
-		attn_enable();
-
-	/* check if the host wants it */
-	if (BIF_IN(FSTT_CLR) & HOST_STATUS_BIT) {
-		/* the host wants it - don't get it yet  */
-		waiting_for_bif = 1;
-	} else {
-		/* the host doesn't want it - just set bus request */
-		waiting_for_bif = 0;
-		BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR);
-		while (!HAVE_BIF() && !BIF_BUSY()) ;
-		DEBUG(("|set bif request\n"));
-	}
-	restore_flags(flags);
-	return;
-#endif
-
-#if TOKEN_ARBITRATION
-	if (net_started && !have_token) {
-		BIF_OUT(FSTT_CLR,HOST_STATUS_BIT);
-		restore_flags(flags);
-		return;
-	}
-	BIF_OUT(FSTT_SET,HOST_STATUS_BIT);
-#endif
-
-	BIF_OUT(BIF_SDCSR,BIF_SDCSR_BR);
-	restore_flags(flags);
-}
-
-#define BIF_NOCOPY (1<<0)
-
-/* a queue of requests that need to be sent over the bif. Needs to be
-modified sometime to allow the direct queueing of skb's */
-struct bif_queue {
-	volatile struct bif_queue *next;
-	struct cap_request req;
-	char *data;
-	int data_size;
-	int flags;
-};
-
-static volatile struct bif_queue *bif_queue_top = NULL;
-static volatile struct bif_queue *bif_queue_end = NULL;
-
-static struct sk_buff *skb_out = NULL;
-static struct sk_buff *skb_in = NULL;
-static char *bif_dma_data = NULL;
-static int bif_dma_out_size = 0;
-
-
-/* send waiting elements. Called mainly when we get a bif "bus get"
-   interrupt to say we now have the bus */
-static void bif_intr_runqueue(void)
-{
-	unsigned flags;
-	
-	/* if I don't have the bus then return */
-	if (!HAVE_BIF())
-		return;
-	
-	if (dma_state != DMA_IDLE) return;
-	
-	save_flags(flags); cli();
-	
-	while (bif_queue_top) {
-		volatile struct bif_queue *q = bif_queue_top;
-		bif_queue_top = q->next;
-
-		/* printk("|queue run (length=%d)\n",queue_length); */
-		queue_length--;
-
-		if (!q->data) {
-			/* use programmed IO for small requests */
-			write_bif((char *)&q->req,sizeof(q->req),1,1);
-			kfree_s((char *)q,sizeof(*q));
-			continue;
-		}
-
-		if (q->flags & BIF_NOCOPY) {
-			write_bif((char *)&q->req,sizeof(q->req),1,0);
-		}
-
-		if (use_dma && q->data_size > DMA_THRESHOLD) {
-			dma_state = DMA_OUTGOING;
-			if (q->req.type == REQ_IP) {
-				skb_out = (struct sk_buff *)q->data;
-				ap_dma_go(DMA_CH2,(unsigned)skb_out->data,
-					  q->data_size,DMA_DCMD_TD_MD);
-			} else {
-				if (!(q->flags & BIF_NOCOPY)) {
-					bif_dma_data = q->data;
-					bif_dma_out_size = q->data_size;
-				}
-				ap_dma_go(DMA_CH2,(unsigned)q->data,
-					  q->data_size,DMA_DCMD_TD_MD);
-			}
-			kfree_s((char *)q,sizeof(*q));
-			restore_flags(flags);
-			return; /* wait for DMA to complete */
-		} 
-
-		if (q->req.type == REQ_IP) {
-			struct sk_buff *skb = (struct sk_buff *)q->data;
-			write_bif(skb->data,q->data_size,1,1);       
-			dev_kfree_skb(skb);
-		} else {
-			write_bif(q->data,q->data_size,1,1);
-			if (!(q->flags & BIF_NOCOPY))
-				kfree_s(q->data,q->data_size);	
-		}
-		kfree_s((char *)q,sizeof(*q));
-	}
-  
-	/* I don't want the bus now */
-	release_bif(); 
-	restore_flags(flags);
-}
-
-
-static void queue_attach(struct bif_queue *q)
-{
-	unsigned flags;
-	save_flags(flags); cli();
-	
-	/* attach it to the end of the queue */
-	if (!bif_queue_top) {
-		bif_queue_top = q;
-	} else {
-		bif_queue_end->next = q;
-	}
-	bif_queue_end = q;
-
-	queue_length++;
-
-	/* printk("|queue add (length=%d)\n",queue_length); */
-
-	/* tell the bus we want access */
-	want_bif();
-
-	restore_flags(flags);  
-}
-
-
-/* queue an element for sending over the bif. */
-int bif_queue(struct cap_request *req,char *buf,int bufsize)
-{
-	struct bif_queue *q;
-
-	if (req->header == 0)
-		req->header = MAKE_HEADER(HOST_CID);
-	
-	/* if we aren't running interrupt driven then just send it 
-	   immediately */
-	if (!interrupt_driven) {
-		write_bif_polled((char *)req,sizeof(*req),buf,bufsize);
-		return(0);
-	}
-
-	/* allocate a queue element */
-	q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC);
-	if (!q) {
-		/* yikes! */
-		return(-ENOMEM);
-	}
-	
-	q->flags = 0;
-	q->data = NULL;
-	q->data_size = 0;
-	
-	if (buf && bufsize>0) {
-		q->data_size = bufsize+sizeof(*req);
-		q->data = (char *)kmalloc(q->data_size,GFP_ATOMIC);
-		if (!q->data) {
-			kfree_s(q,sizeof(*q));
-			return(-ENOMEM);
-		}
-	}
-
-	q->req = *req;
-	if (buf&&bufsize) {
-		memcpy(q->data,(char *)req,sizeof(*req));
-		memcpy(q->data+sizeof(*req),buf,bufsize);
-	}
-	q->next = NULL;
-	
-	queue_attach(q);
-
-	return(0);
-}
-
-
-/* queue an element for sending over the bif. */
-int bif_queue_nocopy(struct cap_request *req,char *buf,int bufsize)
-{
-	struct bif_queue *q;
-
-	if (req->header == 0)
-		req->header = MAKE_HEADER(HOST_CID);
-	
-	/* allocate a queue element */
-	q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC);
-	if (!q) {
-		return(-ENOMEM);
-	}
-	
-	q->data = buf;
-	q->data_size = bufsize;
-	q->flags = BIF_NOCOPY;
-	q->req = *req;
-	q->next = NULL;
-	
-	queue_attach(q);
-
-	return(0);
-}
-
-
-/* put an IP packet into the bif queue */
-int bif_send_ip(int cid, struct sk_buff *skb)
-{
-	struct cap_request *req = (struct cap_request *)skb->data;
-	struct bif_queue *q;
-	u_long destip;
-
-	destip = *(u_long *)(skb->data+sizeof(*req)+16);
-
-	if (cid != -1) {
-		req->header = MAKE_HEADER(cid);
-	} else if (destip == (cap_init.baseIP | ~cap_init.netmask)) {
-		req->header = BIF_HEADER_IN | BIF_HEADER_BR;    
-	} else {
-		req->header = MAKE_HEADER(HOST_CID);    
-	}
-	
-	/* allocate a queue element */
-	q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC);
-	if (!q) {
-		/* yikes! */
-		dev_kfree_skb(skb);
-		return(-ENOMEM);
-	}
-	
-	req->size = ROUND4(skb->len);
-	req->cid = mpp_cid();
-	req->type = REQ_IP;
-
-	q->data = (char *)skb;
-	q->data_size = req->size;
-	q->next = NULL;
-	q->req = *req;
-	q->flags = 0;
-	
-	queue_attach(q);
-	
-	return(0);
-}
-
-
-/* send an OPENNET request to tell the front end to open the apnet
-   network interface */
-void start_apnet(void)
-{
-	struct cap_request req;
-	req.cid = mpp_cid();
-	req.type = REQ_OPENNET;
-	req.size = sizeof(req);
-	req.header = MAKE_HEADER(HOST_CID);
-	
-	bif_queue(&req,NULL,0);
-	printk("sent start_apnet request\n");
-}
-
-/* we have received an IP packet - pass it to the bif network
-   interface code */
-static void reply_ip(struct cap_request *req)
-{
-	if (drop_ip_packets || 
-	    !(skb_in = dev_alloc_skb(req->size - sizeof(*req)))) {
-		bif_toss(req->size - sizeof(*req));
-		return;
-	}
-
-	if (use_dma && req->size > DMA_THRESHOLD) {
-		dma_state = DMA_INCOMING;
-		ap_dma_go(DMA_CH2,
-			  (unsigned)skb_put(skb_in,req->size - sizeof(*req)),
-			  req->size - sizeof(*req),DMA_DCMD_TD_DM);
-	} else {
-		read_bif(skb_put(skb_in,req->size - sizeof(*req)),
-			 req->size - sizeof(*req));
-		bif_rx(skb_in);
-		skb_in = NULL;
-	}
-}
-
-
-/* we have received a bread block - DMA it in */
-static void reply_bread(struct cap_request *req)
-{
-	extern char *ap_buffer(struct cap_request *creq);
-	char *buffer;
-	
-	buffer = ap_buffer(req);
-	bread_req = *req;
-	
-	if (use_dma) {
-		dma_state = DMA_INCOMING;
-		ap_dma_go(DMA_CH2,
-			  (unsigned)buffer,req->size - sizeof(*req),
-			  DMA_DCMD_TD_DM);
-	} else {
-		read_bif(buffer,req->size - sizeof(*req));
-		ap_complete(&bread_req);
-		bread_req.type = -1;	  
-	}
-}
-
-
-static struct debug_key {
-	struct debug_key *next;
-	char key;
-	void (*fn)(void);
-	char *description;
-} *debug_keys = NULL;
-
-
-void show_debug_keys(void)
-{
-	struct debug_key *r;
-	for (r=debug_keys;r;r=r->next)
-		printk("%c: %s\n",r->key,r->description);
-}
-
-
-void bif_add_debug_key(char key,void (*fn)(void),char *description)
-{
-	struct debug_key *r,*r2;
-	r = (struct debug_key *)kmalloc(sizeof(*r),GFP_ATOMIC);
-	if (r) {
-		r->next = NULL;
-		r->key = key;
-		r->fn = fn;
-		r->description = description;
-		if (!debug_keys) {
-			debug_keys = r;
-		} else {
-			for (r2=debug_keys;
-			     r2->next && r2->key != key;r2=r2->next) ;
-
-			if (r2->key == key) {
-				r2->fn = fn;
-				r2->description = description;
-				kfree_s(r,sizeof(*r));
-			} else {
-				r2->next = r;
-			}
-		}
-	}
-}
-
-/* these are very useful for debugging ! */
-static void reply_putchar(struct cap_request *req)
-{  
-	struct debug_key *r;
-
-	char c = req->data[0];
-
-	ap_set_user(req->data[1]);
-
-	for (r=debug_keys;r;r=r->next)
-		if (r->key == c) {
-			r->fn();
-			break;
-		}      
-	if (!r)
-		printk("cell %d got character %d [%c]\n",mpp_cid(),(int)c,c);
-
-	ap_set_user(-1);
-}
-
-
-/* send a signal to a task by name or pid */
-static void reply_kill(struct cap_request *req)
-{  
-  int sig = req->data[0];
-  struct task_struct *p;
-  int len;
-  char name[32];
-
-  len = req->size - sizeof(*req);
-  if (len == 0) {
-    int pid = req->data[1];
-    p = find_task_by_pid(pid);
-
-    if(p)
-	    send_sig(sig, p, 1);
-    else
-	    printk("cell %d: no task with pid %d\n",mpp_cid(),pid);
-    return;
-  }
-
-  if (len > sizeof(name)-1) {
-    bif_toss(len);
-    return;
-  }
-
-  read_bif(name,len);
-  name[len] = 0;
-
-  read_lock(&tasklist_lock);
-  for_each_task(p) 
-    if (strcmp(name,p->comm) == 0)
-      send_sig(sig,p,1);
-  read_unlock(&tasklist_lock);
-}
-
-
-static struct req_list {
-	struct req_list *next;
-	int type;
-	void (*fn)(struct cap_request *);
-} *reg_req_list = NULL;
-
-
-void bif_register_request(int type,void (*fn)(struct cap_request *))
-{
-	struct req_list *r,*r2;
-	r = (struct req_list *)kmalloc(sizeof(*r),GFP_ATOMIC);
-	if (r) {
-		r->next = NULL;
-		r->type = type;
-		r->fn = fn;
-		if (!reg_req_list) {
-			reg_req_list = r;
-		} else {
-			for (r2=reg_req_list;
-			     r2->next && r2->type != type;r2=r2->next) ;
-
-			if (r2->type == type) {
-				r2->fn = fn;
-				kfree_s(r,sizeof(*r));
-			} else {
-				r2->next = r;
-			}
-		}
-	}
-}
-
-
-
-/* a request has come in on the bif - process it */
-static void bif_intr_receive(struct cap_request *req1)
-{
-	struct req_list *r;
-	extern void ap_open_reply(struct cap_request *creq);  
-	struct cap_request req;
-
-	if (req1) {
-		req = *req1;
-	} else {
-		/* read the main cap request header */
-		read_bif((char *)&req,sizeof(req));
-	}
-
-	/* service it */
-	switch (req.type)
-	{
-	case REQ_PUTCHAR:
-		reply_putchar(&req);
-		break;
-	case REQ_KILL:
-		reply_kill(&req);
-		break;
-	case REQ_BREAK:
-		breakpoint();
-		break;
-	case REQ_IP:
-		reply_ip(&req);
-		break;
-#if TOKEN_ARBITRATION
-	case REQ_BIF_TOKEN:
-		have_token = 1;
-		want_bif();
-		break;
-#endif
-	case REQ_OPENNET:
-		net_started = 1;
-		break;
-	case REQ_BREAD:
-		reply_bread(&req);
-		break;
-	case REQ_BOPEN:
-		ap_open_reply(&req);
-		break;
-	case REQ_BWRITE:
-		ap_complete(&req);
-		break;
-	case REQ_SCHEDULE:
-		mpp_schedule(&req);
-		break;
-
-	default:
-		for (r=reg_req_list;r;r=r->next)
-			if (r->type == req.type) {
-				r->fn(&req);
-				return;
-			}
-		printk("Unknown request %d\n",req.type);
-		break;
-	}
-}
-
-
-static void bif_dma_complete(void)
-{
-	extern int bif_rx(struct sk_buff *skb);
-	enum dma_state old_state = dma_state;
-	unsigned a;
-	
-	a = DMA_IN(DMA2_DMST);
-	
-	if (a & DMA_DMST_AC) return;
-	
-	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_NORMAL_SH);
-	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_ERROR_SH);
-	
-	if (old_state == DMA_INCOMING) {
-		if (skb_in) bif_rx(skb_in);
-		skb_in = NULL;
-	}
-	if (bread_req.type != -1) {
-		ap_complete(&bread_req);
-		bread_req.type = -1;
-	}
-
-	if (bif_dma_data) {
-		kfree_s(bif_dma_data,bif_dma_out_size);
-		bif_dma_data = NULL;
-	}
-	
-	if (skb_out) {
-		dev_kfree_skb(skb_out);
-		skb_out = NULL;
-	}
-	
-	dma_state = DMA_IDLE;
-	
-	if (a & (AP_INTR_REQ<<DMA_INTR_ERROR_SH)) {
-		printk("BIF: got dma error\n");
-	}
-}
-
-
-/* handle bif related interrupts. Currently handles 3 interrupts, the
-   bif header interrupt, the bif get interrupt and the dma transfer
-   complete interrupt */
-static void bif_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned flags;
-	
-	bif_pt_regs = regs;                       
-	
-	save_flags(flags); cli();
-
-	mac_dma_complete();
-
-	if (dma_state != DMA_IDLE) {
-		bif_dma_complete();
-	}
-	
-	bif_reset_interrupts();
-	
-	while (dma_state == DMA_IDLE && BIF_DATA_WAITING()) {
-		bif_intr_receive(NULL);
-	}
-
-	if (dma_state != DMA_IDLE) {
-		bif_dma_complete();
-	}
-	
-	if (dma_state == DMA_IDLE && bif_queue_top && !HAVE_BIF()) {
-		want_bif();
-	}
-	
-	if (dma_state == DMA_IDLE && HAVE_BIF()) { 
-		waiting_for_bif = 0;
-		bif_intr_runqueue(); 
-	}
-
-	if (dma_state == DMA_IDLE && HAVE_BIF()) {
-		release_bif();
-	}
-
-	restore_flags(flags);
-	bif_pt_regs = NULL;
-}
-
-
-/* handle the attention interrupt - used for BIF arbitration */
-static void attn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned flags;
-
-	save_flags(flags); cli();
-
-	attn_enable();
-
-#if SNET_ARBITRATION
-	attn_mask();
-	DEBUG(("|bif attn irq %d\n",irq));
-
-	if (waiting_for_bif)
-		want_bif();
-
-	DEBUG(("|bif attn irq %d done\n",irq));
-#endif
-
-	bif_interrupt(irq,dev_id,regs);
-	restore_flags(flags);
-}
-
-
-void bif_timer(void)
-{
-#if 1
-	if (interrupt_driven)
-		bif_interrupt(0,NULL,NULL);
-#endif
-}
-
-static void tnet_ip_enable(void)
-{ 
-	tnet_ip_enabled = 1; 
-	printk("tnet_ip_enabled=%d\n",tnet_ip_enabled);
-}
-
-static void tnet_ip_disable(void)
-{ 
-	tnet_ip_enabled = 0; 
-	printk("tnet_ip_enabled=%d\n",tnet_ip_enabled);
-}
-
-/* initialise the bif code */
-void ap_bif_init(void)
-{
-	int res;
-	unsigned long flags;
-	printk("doing ap_bif_init()\n");
-	
-	bif_add_debug_key('+',tnet_ip_enable,"enable Tnet based IP");
-	bif_add_debug_key('-',tnet_ip_disable,"disable Tnet based IP");
-	
-	save_flags(flags); cli();
-	
-	/* register the BIF interrupt */
-	if ((res=request_irq(APBIF_IRQ, bif_interrupt, 
-			     SA_INTERRUPT, "apbif", NULL))) {
-		printk("Failed to install bif interrupt handler\n");
-		restore_flags(flags);
-		return;
-	}
-
-	/* and the bus get interrupt */
-	if ((res=request_irq(APBIFGET_IRQ, bif_interrupt, 
-			     SA_INTERRUPT, "apbifget", NULL))) {
-		printk("Failed to install bifget interrupt handler\n");
-		restore_flags(flags);
-		return;
-	}
-
-	/* dma complete interrupt */
-	if ((res=request_irq(APDMA_IRQ, bif_interrupt, SA_INTERRUPT, 
-			     "apdma", NULL))) {
-		printk("Failed to install bifdma interrupt handler\n");
-		restore_flags(flags);
-		return;
-	}
-
-	/* attention interrupt */
-	if ((res=request_irq(APATTN_IRQ, attn_interrupt, SA_INTERRUPT, 
-			     "apattn", NULL))) {
-		printk("Failed to install apattn interrupt handler\n");
-		restore_flags(flags);
-		return;
-	}
-
-	printk("Installed bif handlers\n");
-
-	/* enable dma-request */
-	BIF_OUT(BIF_SDCSR,BIF_SDCSR_DE);
-	
-	DMA_OUT(DMA2_DCMD,DMA_DCMD_SA);	
-	DMA_OUT(DMA2_DMST,DMA_DMST_RST);
-	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_NORMAL_SH);
-	DMA_OUT(DMA2_DMST,AP_CLR_INTR_MASK<<DMA_INTR_NORMAL_SH);
-	DMA_OUT(DMA2_DMST,AP_CLR_INTR_REQ<<DMA_INTR_ERROR_SH);
-	DMA_OUT(DMA2_DMST,AP_CLR_INTR_MASK<<DMA_INTR_ERROR_SH);
-
-	/* enable the attention interrupt */
-	attn_enable();
-	
-	DMA_OUT(DMA_BIF_BCMD,DMA_BCMD_SA);
-	DMA_OUT(DMA_BIF_BRST,DMA_DMST_RST);
-	
-	/* from now on we are interrupt driven */
-	bread_req.type = -1;
-	dma_state = DMA_IDLE;
-	interrupt_driven = 1;
-	use_dma = 1;
-	bif_reset_interrupts();
-
-	/* if theres something in the queue then we also want the bus */
-	if (bif_queue_top) 
-		want_bif();
-	
-	/* tell the host that networking is now OK */
-	start_apnet();
-	
-	printk("bif initialised\n");
-	
-	restore_flags(flags);
-}
-
-
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/dma.c linux/arch/sparc/ap1000/dma.c
--- v2.3.41/linux/arch/sparc/ap1000/dma.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/dma.c	Wed Dec 31 16:00:00 1969
@@ -1,74 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* dma routines for the AP1000 */
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-
-#define DMA_MAX_TRANS_SIZE2 (0xfffffc)
-
-int ap_dma_wait(int ch)
-{
-	int i = 0;
-	while (DMA_IN(ch+DMA_DMST) & DMA_DMST_AC) i++;
-	return i;
-}
-
-/* send some data out a dma channel */
-int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd)
-{
-  int rest;
-
-  p = mmu_v2p(p);
-
-  cmd |= DMA_DCMD_ST | DMA_DCMD_TYP_AUTO;
-
-#if 0
-  if (ap_dma_wait(ch)) {
-	  printk("WARNING: dma started when not complete\n");
-  }
-
-  if (cmd == DMA_DCMD_TD_MD && !(BIF_IN(BIF_SDCSR) & BIF_SDCSR_BG)) {
-	  ap_led(0xAA);
-	  printk("attempt to dma without holding the bus\n");
-	  return -1;
-  }
-#endif
-
-  /* reset the dma system */
-  DMA_OUT(ch + DMA_DMST,DMA_DMST_RST);
-
-  if (size <= DMA_MAX_TRANS_SIZE) {
-    DMA_OUT(ch + DMA_MADDR,(unsigned long)p);
-    DMA_OUT(ch + DMA_HSKIP,1);
-    DMA_OUT(ch + DMA_VSKIP,1);
-    DMA_OUT(ch + DMA_DCMD,cmd | B2W(size));
-    return 0;
-  } 
-
-  if (size <= DMA_MAX_TRANS_SIZE2) {
-    if(size & 0x3) size += 4;
-    rest = (size & (DMA_TRANS_BLOCK_SIZE - 1)) >> 2;
-    if (rest) {
-      DMA_OUT(ch + DMA_HDRP,(unsigned)p);
-      p += rest << 2;
-    }
-    DMA_OUT(ch + DMA_MADDR,(unsigned)p);
-    DMA_OUT(ch + DMA_HSKIP,size >> (2 + 6));
-    DMA_OUT(ch + DMA_VSKIP,1);
-    DMA_OUT(ch + DMA_DCMD,cmd | (rest << 16) | 64);
-    return 0;
-  }
-
-  printk("AP1000 DMA operation too big (%d bytes) - aborting\n",size);
-  return(-1);
-}
-
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/hw.c linux/arch/sparc/ap1000/hw.c
--- v2.3.41/linux/arch/sparc/ap1000/hw.c	Tue May 13 22:41:03 1997
+++ linux/arch/sparc/ap1000/hw.c	Wed Dec 31 16:00:00 1969
@@ -1,200 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Initialize the AP1000 hardware: BIF, MSC+, MC+, etc.
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/mpp.h>
-#include <asm/irq.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-
-#define APLOG 0
-
-/* these make using CellOS code easier */
-int cap_nopt0;
-int cap_cid0;
-int cap_ncel0;
-
-unsigned _cid, _ncel, _ncelx, _ncely, _cidx, _cidy;
-
-/* yuck - needed for sun4c! */
-static unsigned char dummy;
-unsigned char *auxio_register = &dummy;
-
-
-extern struct cap_init cap_init;
-
-static void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-  ap_panic("** unexpected interrupt %d **\n",irq); 
-}
-
-static void ap_other_irqs(void)
-{
-	request_irq(3, unexpected_irq, SA_INTERRUPT, "unused", 0);
-	request_irq(5, unexpected_irq, SA_INTERRUPT, "unused", 0);
-	request_irq(12, unexpected_irq, SA_INTERRUPT, "unused", 0);
-	request_irq(15, unexpected_irq, SA_INTERRUPT, "unused", 0);
-}
-
-int ap_memory_size(void)
-{
-	if ((MSC_IN(MSC_SIMMCHK) & MSC_SIMMCHK_MASK) == 0) {
-		return 16*1024*1024; 
-	}
-	return 64*1024*1024;
-}
-
-static void show_registers(void)
-{
-	extern struct pt_regs *bif_pt_regs;
-	if (bif_pt_regs) 
-		show_regs(bif_pt_regs);
-	else
-		printk("unable to show registers\n");
-}
-
-
-static void check_alive(void)
-{
-	printk("Cell %d is alive\n",mpp_cid());	       
-}
-
-
-
-static void show_task(struct task_struct *t)
-{
-	printk("cell=%3d uid=%5d pid=%5d utime=%3d stime=%3d etime=%3d name=%s\n",
-	       mpp_cid(),
-	       t->uid,
-	       (int)t->pid,
-	       (int)t->utime,
-	       (int)t->stime,
-	       (jiffies - (int)t->start_time) / 100,
-	       t->comm);
-}
-
-static void show_ptasks(void)
-{
-	extern struct task_struct *task[];
-	struct task_struct *p;
-	int i;
-	int count=0;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		struct task_struct **tp = p->tarray_ptr;
-
-		if(tp >= &task[MPP_TASK_BASE]) {
-			show_task(p);
-			count++;
-		}
-	}
-	read_unlock(&tasklist_lock);
-
-	if (count == 0)
-		printk("no parallel tasks on cell %d\n",mpp_cid());
-}
-
-static void show_utasks(void)
-{
-	extern struct task_struct *task[];
-	struct task_struct *p;
-	int i;
-	int count=0;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if(p->uid > 1) {
-			show_task(task[i]);
-			count++;
-		}
-	}
-	read_unlock(&tasklist_lock);
-
-	if (count == 0)
-		printk("no user tasks on cell %d\n",mpp_cid());
-}
-
-
-static void show_otasks(void)
-{
-	extern struct task_struct *task[];
-	struct task_struct *p;
-	int i;
-	int count=0;
-	extern int ap_current_uid;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if(p->uid == ap_current_uid) {
-			show_task(task[i]);
-			count++;
-		}
-	}
-	read_unlock(&tasklist_lock);
-
-	if (count == 0)
-		printk("no tasks on cell %d\n",mpp_cid());
-}
-
-
-void do_panic(void)
-{
-	int *x = 0;
-	*x = 1; /* uggh */
-}
-
-
-void mpp_hw_init(void)
-{
-	extern void show_state(void);
-	extern void breakpoint(void);
-	extern void ctrl_alt_del(void);
-	extern void mac_print_state(void);
-	extern void show_debug_keys(void);
-	
-	bif_add_debug_key('c',check_alive,"check if a cell is alive");
-	bif_add_debug_key('k',show_debug_keys,"show the kernel debug keys");
-	bif_add_debug_key('p',show_registers,"show register info");
-	bif_add_debug_key('p',show_registers,"show register info");
-	bif_add_debug_key('m',show_mem,"detailed memory stats");
-	bif_add_debug_key('s',show_state,"detailed process stats");
-	bif_add_debug_key('D',ap_start_debugger,"launch the kernel debugger");
-	bif_add_debug_key('i',breakpoint,"send a breakpoint");
-	bif_add_debug_key('r',ctrl_alt_del,"run shutdown (doesn't work)");  
-	bif_add_debug_key('P',show_ptasks,"show running parallel tasks");  
-	bif_add_debug_key('U',show_utasks,"show all user tasks");  
-	bif_add_debug_key('O',show_otasks,"show own user tasks");  
-	bif_add_debug_key('^',do_panic,"panic :-)");  
-	
-	
-	cap_cid0 = BIF_IN(BIF_CIDR1);
-	cap_ncel0 = cap_init.numcells;
-	
-	_cid = cap_cid0;
-	_ncel = cap_ncel0;
-	_ncelx = _ncel<8?_ncel:8;
-	_ncely = ((_ncel-1) / _ncelx) + 1;
-	_cidx = _cid % _ncelx;
-	_cidy = _cid / _ncelx;
-	
-	ap_bif_init();
-	ap_msc_init();
-	ap_tnet_init();
-	ap_profile_init();
-	ap_other_irqs();
-	ap_ringbuf_init();
-#if APLOG
-	ap_log(NULL,-1);
-#endif
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/irq.c linux/arch/sparc/ap1000/irq.c
--- v2.3.41/linux/arch/sparc/ap1000/irq.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/irq.c	Wed Dec 31 16:00:00 1969
@@ -1,64 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/linkage.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/malloc.h>
-
-#include <asm/ptrace.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/psr.h>
-#include <asm/vaddrs.h>
-#include <asm/timer.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/traps.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/ap1000/apreg.h>
-
-extern void ap_clear_clock_irq(void);
-extern void ap_init_timers(void);
-
-static void ap_enable_irq(unsigned int irq_nr)
-{
-  /* printk("ENABLE IRQ %d IGNORED\n",irq_nr); */
-}
-
-static void ap_disable_irq(unsigned int irq_nr)
-{
-  printk("DISABLE IRQ %d IGNORED\n",irq_nr);
-}
-
-static void ap_clear_profile_irq(void)
-{
-  MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH);
-}
-
-static void ap_load_profile_irq(unsigned limit)
-{
-  MC_OUT(MC_ITIMER0,limit); 
-}
-
-void ap_init_IRQ(void)
-{
-  enable_irq = ap_enable_irq;
-  disable_irq = ap_disable_irq;
-  clear_clock_irq = ap_clear_clock_irq;
-  clear_profile_irq = ap_clear_profile_irq;
-  load_profile_irq = ap_load_profile_irq;
-  init_timers = ap_init_timers;
-
-  sti(); /* the sun4m code does this, so we do too */
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/kgdb.c linux/arch/sparc/ap1000/kgdb.c
--- v2.3.41/linux/arch/sparc/ap1000/kgdb.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/kgdb.c	Wed Dec 31 16:00:00 1969
@@ -1,78 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* routines to support remote kgdb to Linux/AP+ cells */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-
-static char out_buf[0x100];
-static int out_buf_pos = 0;
-
-static char in_buf[0x100];
-static int in_buf_pos = 0;
-static int in_buf_count = 0;
-
-static int hash_pos = -1;
-
-void ap_dbg_flush(void)
-{
-	struct cap_request req;
-	
-	if (out_buf_pos == 0) return;
-	
-	req.cid = mpp_cid();
-	req.type = REQ_PUTDEBUGSTRING;
-	req.size = sizeof(req) + out_buf_pos;
-	req.header = MAKE_HEADER(HOST_CID);
-	
-	write_bif_polled((char *)&req,sizeof(req),(char *)out_buf,out_buf_pos);
-	
-	out_buf_pos = 0;
-	hash_pos = -1;
-}
-
-/* called by the gdb stuff */
-void putDebugChar(char c)
-{
-	if (c == '#') hash_pos = out_buf_pos;
-	
-	out_buf[out_buf_pos++] = c;
-	if (out_buf_pos == sizeof(out_buf)) {
-		ap_dbg_flush();
-	}
-}
-
-/* used by gdb to get input */
-char getDebugChar(void)
-{
-	unsigned flags;
-	struct cap_request req;
-	
-	ap_dbg_flush();
-	
-	if (in_buf_count == 0) {
-		req.cid = mpp_cid();
-		req.type = REQ_GETDEBUGCHAR;
-		req.size = sizeof(req);
-		req.header = MAKE_HEADER(HOST_CID);
-		
-		save_flags(flags); cli();
-		write_bif_polled((char *)&req,sizeof(req),NULL,0);
-		ap_wait_request(&req,REQ_GETDEBUGCHAR);
-		read_bif(in_buf,req.size - sizeof(req));
-		in_buf_pos = 0;
-		in_buf_count = req.size - sizeof(req);
-		restore_flags(flags);
-	}
-	
-	in_buf_count--;
-	return(in_buf[in_buf_pos++]);
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/mpp.c linux/arch/sparc/ap1000/mpp.c
--- v2.3.41/linux/arch/sparc/ap1000/mpp.c	Tue Aug  4 16:03:34 1998
+++ linux/arch/sparc/ap1000/mpp.c	Wed Dec 31 16:00:00 1969
@@ -1,83 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * simple mpp functions for the AP+
- */
-
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/apservice.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <asm/pgtable.h>
-
-extern int cap_cid0;
-extern int cap_ncel0;
-extern struct cap_init cap_init;
-
-static volatile int mpp_current_task = 0;
-static int gang_factor = DEF_GANG_FACTOR;
-static int last_task = 0;
-
-
-void mpp_schedule(struct cap_request *req)
-{
-	mpp_current_task = req->data[0];
-	current->need_resched = 1;
-	mark_bh(TQUEUE_BH);
-}
-
-
-void mpp_notify_schedule(struct task_struct *tsk)
-{
-	last_task = tsk->taskid;
-
-	msc_switch_check(tsk);
-
-	if (gang_factor == 0) return;
-
-	if (cap_cid0 == cap_init.bootcid && 
-	    mpp_current_task != tsk->taskid) {
-		struct cap_request req;
-
-		mpp_current_task = tsk->taskid;
-	
-		req.cid = mpp_cid();
-		req.type = REQ_SCHEDULE;
-		req.size = sizeof(req);
- 		req.header = MAKE_HEADER(-1);
-		req.data[0] = mpp_current_task;
-		
-		bif_queue(&req,NULL,0);
-	}
-}
-
-
-int mpp_weight(struct task_struct *tsk)
-{
-	extern int block_parallel_tasks;
-
-	if (!MPP_IS_PAR_TASK(tsk->taskid)) return 0;
-
-	if (block_parallel_tasks) return -1000;
-
-	/* XXX task[] fixme */
-	if (last_task && last_task != tsk->taskid && task[last_task] &&
-	    !msc_switch_ok()) return -1000;
-
-	if (cap_cid0 != cap_init.bootcid &&
-	    tsk->taskid != mpp_current_task) {
-		return -gang_factor;
-	}
-	return 0;
-}
-
-void mpp_set_gang_factor(int factor)
-{
-	gang_factor = factor;
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c
--- v2.3.41/linux/arch/sparc/ap1000/msc.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sparc/ap1000/msc.c	Wed Dec 31 16:00:00 1969
@@ -1,1262 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Routines to control the AP1000+ Message Controller (MSC+)
- * and Memory Controller (MC+).
- *
- */
-#define _APLIB_
-#include <asm/ap1000/apreg.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/ap1000/pgtapmmu.h>
-#include <linux/threads.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs);
-static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs);
-static void msc_set_ringbuf(int context);
-static void msc_update_read_ptr(int context,int overflow);
-static void fail_write(int context,int intr,unsigned vaddr);
-static void fail_read(int context,int intr,unsigned vaddr);
-static void msc_switch_from_check(struct task_struct *tsk);
-static void msc_status(void);
-
-#define DEBUG 0
-
-/*
- * This describes how the 5 queues for outgoing requests
- * are mapped into the 256 words of send queue RAM in the MSC+.
- */
-#define NSENDQUEUES		5
-
-static struct send_queues {
-    int	base;		/* must be a multiple of size */
-    int size;		/* must be 32 or 64 */
-} send_queues[NSENDQUEUES] = {
-    {0, 64},		/* System put/send requests */
-    {192, 32},		/* Remote read/write requests */
-    {64, 64},		/* User put/send requests */
-    {224, 32},		/* Remote read replies */
-    {128, 64},		/* Get replies */
-};
-
-#define NR_RBUFS MSC_NR_RBUFS
-
-static struct {
-  unsigned rbmbwp;
-  unsigned rbmmode;
-  unsigned rbmrp;
-} ringbufs[MSC_NR_RBUFS] = {
-  {MSC_RBMBWP0, MSC_RBMMODE0, MSC_RBMRP0},
-  {MSC_RBMBWP1, MSC_RBMMODE1, MSC_RBMRP1},
-  {MSC_RBMBWP2, MSC_RBMMODE2, MSC_RBMRP2},
-};
-
-#define CTX_MASK	0xfff
-#define NULL_CONTEXT	CTX_MASK
-
-#define QOF_ORDER       3	/* 32kB queue overflow buffer */
-#define QOF_SIZE	((1<<QOF_ORDER)*PAGE_SIZE)
-#define QOF_ELT_SIZE	8	/* size of each queue element */
-#define QOF_REDZONE_SZ	8192	/* 8kB redzone, imposed by hardware */
-#define QOF_NELT	(QOF_SIZE / QOF_ELT_SIZE)
-#define QOF_RED_NELT	(QOF_REDZONE_SZ / QOF_ELT_SIZE)
-#define QOF_GREEN_NELT	((QOF_SIZE - QOF_REDZONE_SZ) / QOF_ELT_SIZE)
-
-#define MAKE_QBMPTR(qof, size) \
-	(MKFIELD((qof) >> 19, MSC_QBMP_BP) \
-	 + MKFIELD((qof) >> 3, MSC_QBMP_WP) \
-	 + MKFIELD(((qof) + (size) - 1) >> 13, MSC_QBMP_LIM))
-
-#define QBM_UPDATE_WP(wp)	\
-	MSC_OUT(MSC_QBMPTR, INSFIELD(MSC_IN(MSC_QBMPTR), (unsigned)(wp) >> 3, \
-				     MSC_QBMP_WP))
-
-/* Send queue overflow buffer structure */
-struct qof_elt {
-    unsigned info;
-    unsigned data;
-};
-
-/* Fields in qof_elt.info */
-#define QOF_QUEUE_SH	24		/* queue bits start at bit 24 */
-#define QOF_QUEUE_M	0x1f		/* 5 bits wide */
-#define QOF_ENDBIT	1		/* end bit in bit 0 */
-
-static struct qof_elt *qof_base=NULL; /* start of overflow buffer */
-static unsigned long  qof_phys;	/* physical start adrs of overflow buffer */
-static struct qof_elt *qof_rp;	/* read pointer for refills */
-static struct qof_elt *qof_new;	/* first element we haven't yet looked at */
-static int qof_present[NSENDQUEUES];/* # elts for each q in [qof_rp,qof_new) */
-
-/* this is used to flag when the msc is blocked, so we can't send 
-   messages on it without the possability of deadlock */
-int msc_blocked = 0;
-int block_parallel_tasks = 0;
-
-static int qbm_full_counter = 0;
-
-#define INTR_LIMIT 10000
-static int intr_counter = 0;
-static unsigned intr_mask;
-
-#define DUMMY_RINGBUF_ORDER 5
-#define DUMMY_RINGBUF_SIZE ((1<<DUMMY_RINGBUF_ORDER)*PAGE_SIZE)
-
-/* 
- * The system ring buffer, used for inter-kernel comms 
- */
-struct ringbuf_struct system_ringbuf = {NULL,NULL,SYSTEM_RINGBUF_ORDER,0,0,0,0};
-struct ringbuf_struct dummy_ringbuf = {NULL,NULL,DUMMY_RINGBUF_ORDER,0,0,0,0};
-unsigned system_read_ptr = (SYSTEM_RINGBUF_SIZE>>5)-1;
-unsigned dummy_read_ptr = (DUMMY_RINGBUF_SIZE>>5)-1;
-
-#define SQ_NEW_MODE(mode) do { \
-    MSC_OUT(MSC_SQCTRL, ((MSC_IN(MSC_SQCTRL) & ~MSC_SQC_RMODE) \
-			 | MSC_SQC_RMODE_ ## mode)); \
-    while ((MSC_IN(MSC_SQCTRL) & MSC_SQC_MODE) != MSC_SQC_MODE_ ## mode) \
-	/* hang */ ; \
-} while (0)
-
-/* Repack the queue overflow buffer if >= this many already-used entries */
-#define REPACK_THRESH	64
-
-
-static void refill_sq(void);
-static void repack_qof(void);
-static void shuffle_qof(void);
-static void async_callback(int, unsigned long, int, int);
-
-
-static void mask_all_interrupts(void)
-{
-    /* disable all MSC+ interrupts */
-    MSC_OUT(MSC_INTR, 
-	    (AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH) |
-	    (AP_SET_INTR_MASK << MSC_INTR_SQFILL_SH) |
-	    (AP_SET_INTR_MASK << MSC_INTR_RBMISS_SH) |
-	    (AP_SET_INTR_MASK << MSC_INTR_RBFULL_SH) |
-	    (AP_SET_INTR_MASK << MSC_INTR_RMASF_SH) |
-	    (AP_SET_INTR_MASK << MSC_INTR_RMASE_SH) |
-	    (AP_SET_INTR_MASK << MSC_INTR_SMASF_SH) |
-	    (AP_SET_INTR_MASK << MSC_INTR_SMASE_SH));
-}
-
-static inline int valid_task(struct task_struct *tsk)
-{
-  return(tsk && 
-	 !((tsk)->flags & PF_EXITING) && 
-	 tsk->mm && 
-	 tsk->mm->context != NO_CONTEXT);
-}
-
-static inline unsigned long apmmu_get_raw_ctable_ptr(void)
-{
-	unsigned int retval;
-
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (retval) :
-			     "r" (APMMU_CTXTBL_PTR),
-			     "i" (ASI_M_MMUREGS));
-	return (retval);
-}
-
-static void mc_tlb_map(unsigned phys_page,unsigned vpage,int context)
-{
-    unsigned long long *tlb4k;
-    unsigned long long new_entry;
-    unsigned long *new_entryp = (unsigned long *)&new_entry;
-    tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF);
-    new_entryp[0] = (phys_page&~7) >> 3;
-    new_entryp[1] = ((phys_page & 7) << 29) | (((vpage>>8)&0xFFF) << 17) | 
-	(context << 5) | 0x13; 
-    tlb4k[0] = new_entry;
-#if DEBUG
-    printk("mc_tlb_map(%x,%x,%x) %x %x at %x\n",
-	   phys_page,vpage,context,new_entryp[0],new_entryp[1],tlb4k);
-#endif
-}
-
-static void mc_tlb_unmap(unsigned vpage)
-{
-	unsigned long long *tlb4k = (unsigned long long *)MC_MMU_TLB4K;
-	tlb4k = ((unsigned long long *)MC_MMU_TLB4K) + (vpage & 0xFF);
-	tlb4k[0] = 0;
-}
-
-void mc_tlb_init(void)
-{
-	unsigned long long *tlb256k, *tlb4k;
-	int i;
-	
-	tlb4k = (unsigned long long *)MC_MMU_TLB4K;
-	for (i = MC_MMU_TLB4K_SIZE; i > 0; --i)
-		*tlb4k++ = 0;
-	tlb256k = (unsigned long long *)MC_MMU_TLB256K;
-	for (i = MC_MMU_TLB256K_SIZE; i > 0; --i)
-		*tlb256k++ = 0;
-}
-
-void ap_msc_init(void)
-{
-    int i, flags, res;
-    unsigned int qp;
-
-    bif_add_debug_key('M',msc_status,"MSC+ status");
-
-#if DEBUG
-    printk("MSC+ version %x\n", MSC_IN(MSC_VERSION));
-    printk("MC+  version %x\n", MC_IN(MC_VERSION));
-#endif
-
-    mc_tlb_init();
-
-    /* Set the MC's copy of the context table pointer */
-    MC_OUT(MC_CTP, apmmu_get_raw_ctable_ptr());
-
-    /* Initialize the send queue pointers */
-    qp = MSC_SQPTR0;
-    for (i = 0; i < 5; ++i) {
-	MSC_OUT(qp, ((send_queues[i].size == 64? MSC_SQP_MODE: 0)
-		     + ((send_queues[i].base >> 5) << MSC_SQP_BP_SH)));
-	qp += (MSC_SQPTR1 - MSC_SQPTR0);
-    }
-
-    /* Initialize the send queue RAM */
-    for (i = 0; i < 256; ++i)
-	MSC_OUT(MSC_SQRAM + i * 8, -1);
-
-    if (!qof_base) {
-      qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER);
-      for (i = MAP_NR(qof_base); i <= MAP_NR(((char*)qof_base)+QOF_SIZE-1);++i)
-	set_bit(PG_reserved, &mem_map[i].flags);
-    }
-
-    qof_phys = mmu_v2p((unsigned long) qof_base);
-    MSC_OUT(MSC_QBMPTR, MAKE_QBMPTR((unsigned long)qof_base, QOF_SIZE));
-    qof_rp = qof_base;
-    qof_new = qof_base;
-    for (i = 0; i < NSENDQUEUES; ++i)
-	qof_present[i] = 0;
-
-    SQ_NEW_MODE(NORMAL);	/* Set the send queue to normal mode */
-
-    /* Register interrupt handler for MSC+ */
-    save_flags(flags); cli();
-    res = request_irq(APMSC_IRQ, msc_interrupt_11, SA_INTERRUPT,
-		      "apmsc", NULL);
-    if (res != 0)
-	printk("couldn't register MSC interrupt 11: error=%d\n", res);
-    res = request_irq(APMAS_IRQ, msc_interrupt_9, SA_INTERRUPT,
-		      "apmas", NULL);
-    if (res != 0)
-	printk("couldn't register MSC interrupt 9: error=%d\n", res);
-    restore_flags(flags);
-
-    MSC_OUT(MSC_MASCTRL, 0);
-
-    /* Enable all MSC+ interrupts (for now) */
-    MSC_OUT(MSC_INTR, 
-	    (AP_CLR_INTR_MASK << MSC_INTR_QBMFUL_SH) |
-	    (AP_CLR_INTR_MASK << MSC_INTR_SQFILL_SH) |
-	    (AP_CLR_INTR_MASK << MSC_INTR_RBMISS_SH) |
-	    (AP_CLR_INTR_MASK << MSC_INTR_RBFULL_SH) |
-	    (AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH) |
-	    (AP_CLR_INTR_MASK << MSC_INTR_RMASE_SH) |
-	    (AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH) |
-	    (AP_CLR_INTR_MASK << MSC_INTR_SMASE_SH));
-
-    /* setup invalid contexts */
-    for (i=0; i<MSC_NR_RBUFS; i++)
-      MSC_OUT(ringbufs[i].rbmmode, NULL_CONTEXT);
-
-    MSC_OUT(MSC_SMASREG,0);
-    MSC_OUT(MSC_RMASREG,0);
-
-    if (!system_ringbuf.ringbuf) {
-      system_ringbuf.ringbuf = 
-	(void *)__get_free_pages(GFP_ATOMIC,SYSTEM_RINGBUF_ORDER);
-      for (i=MAP_NR(system_ringbuf.ringbuf);
-	   i<=MAP_NR(system_ringbuf.ringbuf+SYSTEM_RINGBUF_SIZE-1);i++)
-	set_bit(PG_reserved, &mem_map[i].flags);
-      system_ringbuf.write_ptr = mmu_v2p((unsigned)system_ringbuf.ringbuf)<<1;
-    }
-
-    if (!dummy_ringbuf.ringbuf) {
-      dummy_ringbuf.ringbuf = 
-	(void *)__get_free_pages(GFP_ATOMIC,DUMMY_RINGBUF_ORDER);
-      for (i=MAP_NR(dummy_ringbuf.ringbuf);
-	   i<=MAP_NR(dummy_ringbuf.ringbuf+DUMMY_RINGBUF_SIZE-1);i++)
-	set_bit(PG_reserved, &mem_map[i].flags);
-      dummy_ringbuf.write_ptr = mmu_v2p((unsigned)dummy_ringbuf.ringbuf)<<1;
-    }
-}
-
-
-static inline void qbmfill_interrupt(void)
-{
-	MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_QBMFUL_SH);
-	intr_mask &= ~(AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
-
-	SQ_NEW_MODE(THRU);	/* set send queue ctrlr to through mode */
-	refill_sq();		/* refill the send queues */
-	SQ_NEW_MODE(NORMAL);	/* set send queue ctrlr back to normal mode */
-	/* dismiss the interrupt */
-	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SQFILL_SH);
-}
-
-static inline void qbmful_interrupt(void)
-{
-	int nvalid, ntot, q;
-
-	qbm_full_counter++;
-		
-#if DEBUG
-	printk("qbm full interrupt\n"); 
-#endif
-
-	SQ_NEW_MODE(THRU);	/* set send queue ctrlr to through mode */
-	/* stuff as much as we can into the send queue RAM */
-	refill_sq();
-	/* count how many valid words are left in the qof buffer */
-	nvalid = 0;
-	for (q = 0; q < NSENDQUEUES; ++q)
-		nvalid += qof_present[q];
-	if (nvalid >= QOF_GREEN_NELT) {
-#if DEBUG
-		printk("send queue overflow buffer overflow\n");
-#endif
-		MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH);
-		intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
-		current->need_resched = 1;
-		block_parallel_tasks = 1;
-		mark_bh(TQUEUE_BH);
-	}
-	ntot = qof_new - qof_rp;	/* total # words of qof buf used */
-	if (ntot - nvalid >= REPACK_THRESH || ntot >= QOF_GREEN_NELT
-	    || (ntot > nvalid && nvalid >= QOF_GREEN_NELT - REPACK_THRESH)) {
-		repack_qof();
-		if (qof_new - qof_rp != nvalid) {
-			printk("MSC: qof_present wrong\n");
-		}
-	} else if (nvalid > 0) {
-		shuffle_qof();
-	}
-	/* N.B. if nvalid == 0, msc_refill_sq has already reset the QBM's WP */
-	SQ_NEW_MODE(NORMAL);
-
-	/* dismiss the interrupt */
-	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_QBMFUL_SH);
-}
-
-
-static void msc_interrupt_11(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned intr;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-	if (intr_counter++ == INTR_LIMIT) {
-		mask_all_interrupts();
-		printk("too many MSC interrupts\n");
-		restore_flags(flags); 
-		return;
-	}
-
-	intr = MSC_IN(MSC_INTR);
-
-#if DEBUG
-	printk("CID(%d) msc_interrupt_11: intr = %x\n", mpp_cid(), intr);
-#endif
-
-	if (intr & (AP_INTR_REQ << MSC_INTR_RBMISS_SH)) {
-		int context;
-		context = MSC_IN(MSC_RMASREG) >> 20;
-		
-		msc_set_ringbuf(context);
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBMISS_SH);
-	}
-	
-	if (intr & (AP_INTR_REQ << MSC_INTR_RBFULL_SH)) {
-		int context = MSC_IN(MSC_RMASREG) >> 20;
-		msc_update_read_ptr(context,1);	
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RBFULL_SH);
-	}
-	
-	if (intr & (AP_INTR_REQ << MSC_INTR_SQFILL_SH)) {
-		qbmfill_interrupt();
-	}
-	
-	if (intr & (AP_INTR_REQ << MSC_INTR_QBMFUL_SH)) {
-		qbmful_interrupt();
-	}
-
-	restore_flags(flags);
-}
-
-
-void msc_timer(void)
-{
-	/* unmask all the interrupts that are supposed to be unmasked */
-	intr_counter = 0;
-}
-
-/* assumes NSENDQUEUES == 5 */
-static int log2tbl[32] = {
-    -1,  0,  1, -1,  2, -1, -1, -1,
-     3, -1, -1, -1, -1, -1, -1, -1,
-     4, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1
-};
-
-static unsigned long direct_queues[NSENDQUEUES][2] = {
-    { MSC_SYSTEM_DIRECT, MSC_SYSTEM_DIRECT_END },
-    { MSC_REMOTE_DIRECT, MSC_REMOTE_DIRECT_END },
-    { MSC_USER_DIRECT, MSC_USER_DIRECT_END },
-    { MSC_REMREPLY_DIRECT, MSC_REMREPLY_DIRECT_END },
-    { MSC_REPLY_DIRECT, MSC_REPLY_DIRECT_END }
-};
-
-/*
- * Copy entries from the queue overflow buffer back to the send queue.
- * This must be called with the send queue controller in THRU mode.
- */
-static void refill_sq(void)
-{
-    int notfull, use_old;
-    int q, kept_some;
-    int sqp, sqc;
-    struct qof_elt *rp, *qof_wp;
-    int freew[NSENDQUEUES];	/* # free words in each queue */
-
-    /* give parallel tasks another chance */
-    block_parallel_tasks = 0;
-
-    /* get the qbm's write pointer */
-    qof_wp = qof_base + (EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP)
-			 & ((QOF_SIZE - 1) >> 3));
-#if 0
-    printk("refill_sq: rp=%p new=%p wp=%p pres=[",
-	   qof_rp, qof_new, qof_wp);
-    for (q = 0; q < NSENDQUEUES; ++q)
-	printk("%d ", qof_present[q]);
-    printk("]\n");
-#endif
-
-    /* work out which send queues and aren't full */
-    notfull = 0;
-    use_old = 0;
-    for (q = 0; q < NSENDQUEUES; ++q) {
-	sqp = MSC_IN(MSC_SQPTR0 + q * 8);
-	freew[q] = (EXTFIELD(sqp, MSC_SQP_RP) - EXTFIELD(sqp, MSC_SQP_WP) - 1)
-	    & ((sqp & MSC_SQP_MODE)? 0x3f: 0x1f);
-	if (freew[q] > 0)
-	    notfull |= 1 << (q + QOF_QUEUE_SH);
-	use_old += (freew[q] < qof_present[q])? freew[q]: qof_present[q];
-    }
-
-    /*
-     * If there are useful entries in the old part of the overflow
-     * queue, process them.
-     */
-    kept_some = 0;
-    for (rp = qof_rp; rp < qof_new && use_old > 0; ++rp) {
-	if (rp->info & notfull) {
-	    /* Here's one we can stuff back into the send queue */
-	    q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)];
-	    if (q < 0) {
-		printk("bad queue bits in qof info (%x) at %p\n",
-		       rp->info, rp);
-		/* XXX just ignore this entry - should never happen */
-		rp->info = 0;
-		continue;
-	    }
-	    MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data);
-	    if (--freew[q] == 0)
-		notfull &= ~(1 << (q + QOF_QUEUE_SH));
-	    --qof_present[q];
-	    --use_old;
-	    rp->info = 0;
-	} else if (!kept_some && rp->info != 0) {
-	    qof_rp = rp;
-	    kept_some = 1;
-	}
-    }
-
-    /* Trim off any further already-used items. */
-    if (!kept_some) {
-	for (; rp < qof_new; ++rp) {
-	    if (rp->info) {
-		qof_rp = rp;
-		kept_some = 1;
-		break;
-	    }
-	}
-    }
-
-    /*
-     * Now process everything that's arrived since we last updated qof_new.
-     */
-    for (rp = qof_new; rp < qof_wp; ++rp) {
-      if (rp->info == 0)
-	continue;
-	q = log2tbl[EXTFIELD(rp->info, QOF_QUEUE)];
-	if (q < 0) {
-	    printk("bad queue bits in qof info (%x) at %p\n", rp->info, rp);
-	    /* XXX just ignore this entry - should never happen */
-	    rp->info = 0;
-	    continue;
-	}
-	if (rp->info & notfull) {
-	  /* Another one to stuff back into the send queue. */
-	  MSC_OUT(direct_queues[q][rp->info & QOF_ENDBIT],rp->data);
-	  if (--freew[q] == 0)
-	    notfull &= ~(1 << (q + QOF_QUEUE_SH));
-	  rp->info = 0;
-	} else {
-	    ++qof_present[q];
-	    if (!kept_some) {
-		qof_rp = rp;
-		kept_some = 1;
-	    }
-	}
-    }
-
-    /* Update state and the MSC queue-spill flags. */
-    if (!kept_some) {
-	/* queue is empty; avoid unnecessary overflow interrupt later */
-	qof_rp = qof_new = qof_base;
-	QBM_UPDATE_WP(mmu_v2p((unsigned long)qof_base));
-    } else {
-	qof_new = qof_wp;
-    }
-
-    sqc = MSC_IN(MSC_SQCTRL);
-    for (q = 0; q < NSENDQUEUES; ++q)
-	if (qof_present[q] == 0 && freew[q] > 0)
-	    sqc &= ~(1 << (q + MSC_SQC_SPLF_SH));
-    MSC_OUT(MSC_SQCTRL, sqc);
-}
-
-/*
- * Copy the valid entries from their current position
- * in the queue overflow buffer to the beginning.
- * This must be called with the send queue controller in THRU or BLOCKING mode.
- */
-static void repack_qof(void)
-{
-    struct qof_elt *rp, *wp;
-
-    wp = qof_base;
-    for (rp = qof_rp; rp < qof_new; ++rp) {
-	if (rp->info) {
-	    if (rp > wp)
-		*wp = *rp;
-	    ++wp;
-	}
-    }
-    qof_rp = qof_base;
-    qof_new = wp;
-    QBM_UPDATE_WP(wp);
-}
-
-/*
- * Copy all entries from their current position
- * in the queue overflow buffer to the beginning.
- * This must be called with the send queue controller in THRU or BLOCKING mode.
- */
-static void shuffle_qof(void)
-{
-    int n;
-
-    n = qof_new - qof_rp;
-    memmove(qof_base, qof_rp, n * sizeof(struct qof_elt));
-    qof_rp = qof_base;
-    qof_new = qof_base + n;
-    QBM_UPDATE_WP(qof_new);
-}
-
-static inline void handle_signal(int context,unsigned vaddr)
-{
-  int signum = (vaddr - MSC_REM_SIGNAL) >> PAGE_SHIFT;
-  int taskid = MPP_CTX_TO_TASK(context);
-  if (MPP_IS_PAR_TASK(taskid) && valid_task(task[taskid])) {
-    send_sig(signum,task[taskid],1);
-#if DEBUG
-    printk("CID(%d) sent signal %d to task %d\n",mpp_cid(),signum,taskid);
-#endif
-  }
-}
-
-
-/*
- * fail a msc write operation. We use Pauls dirty tlb trick to avoide
- * the msc hardware bugs 
- */
-static void fail_write(int context,int intr,unsigned vaddr)
-{
-	int tsk = MPP_CTX_TO_TASK(context);
-	int vpage = vaddr >> 12;
-#if DEBUG
-	printk("fail write tsk=%d intr=%x vaddr=%x RMASREG=%x errproc=%x\n",
-	       tsk,intr,vaddr,MSC_IN(MSC_RMASREG),MSC_IN(MSC_RHDERRPROC));
-#endif
-
-	mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12),
-		   vpage,context);
-	MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT);
-	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr);
-
-	mc_tlb_unmap(vpage);	
-
-	if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) {
-		if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
-			handle_signal(context,vaddr);
-		} else {
-			task[tsk]->thread.sig_address = vaddr;
-			task[tsk]->thread.sig_desc = SUBSIG_NOMAPPING;
-			send_sig(SIGSEGV, task[tsk], 1);
-		}
-	}
-}
-
-/*
- * fail a msc read operation using the tlb trick */
-static void fail_read(int context,int intr,unsigned vaddr)
-{
-	int tsk = MPP_CTX_TO_TASK(context);  
-#if DEBUG
-	printk("fail read tsk=%d intr=%x\n",tsk,intr);
-#endif
-	
-	mc_tlb_map(0x800000 | (mmu_v2p((unsigned)dummy_ringbuf.ringbuf)>>12),
-		   vaddr>>12,context);
-	MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT);
-	MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << intr);    
-	
-	mc_tlb_unmap(vaddr>>12);
-
-	if (MPP_IS_PAR_CTX(context) && valid_task(task[tsk])) {
-		if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
-			handle_signal(context,vaddr);
-		} else {
-			task[tsk]->thread.sig_address = vaddr;
-			task[tsk]->thread.sig_desc = SUBSIG_NOMAPPING;
-			send_sig(SIGSEGV, task[tsk], 1);
-		}
-	}	
-}
-
-static void async_callback(int tsk,unsigned long vaddr,int write,int ret)
-{
-	unsigned flags;
-	save_flags(flags); cli();
-
-	msc_blocked--;
-	if (write) {
-		intr_mask &= ~(AP_INTR_REQ << MSC_INTR_RMASF_SH);
-		if (ret) {
-			fail_write(MPP_TASK_TO_CTX(tsk),MSC_INTR_RMASF_SH,vaddr);
-			MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH);
-			restore_flags(flags);
-			return;
-		}
-		MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_RFEXIT);
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASF_SH);
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_RMASF_SH);
-	} else {
-		intr_mask &= ~(AP_INTR_REQ << MSC_INTR_SMASF_SH);
-		if (ret) {
-			fail_read(MPP_TASK_TO_CTX(tsk),MSC_INTR_SMASF_SH,vaddr);
-			MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH);
-			restore_flags(flags);
-			return;
-		}
-		MSC_OUT(MSC_MASCTRL, MSC_IN(MSC_MASCTRL) & ~MSC_MASC_SFEXIT);
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH);
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_MASK << MSC_INTR_SMASF_SH);
-	}
-	restore_flags(flags);
-}
-
-
-
-static inline void msc_write_fault(void)
-{
-	unsigned context = MSC_IN(MSC_RMASREG) >> 20;
-	unsigned vaddr = MSC_IN(MSC_RMASTWP)<<12;
-	
-	if (context == SYSTEM_CONTEXT) {
-		fail_write(context,MSC_INTR_RMASF_SH,vaddr);
-		show_mapping_ctx(0,context,vaddr);
-		printk("ERROR: system write fault at %x\n",vaddr);
-		return;
-	}
-		
-	if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
-		fail_write(context,MSC_INTR_RMASF_SH,vaddr);
-		return;
-	}
-		
-	if (MPP_IS_PAR_CTX(context)) {
-		int tsk = MPP_CTX_TO_TASK(context);
-		if (valid_task(task[tsk]) && task[tsk]->ringbuf) {
-			MSC_OUT(MSC_INTR, 
-				AP_SET_INTR_MASK << MSC_INTR_RMASF_SH);
-			intr_mask |= (AP_INTR_REQ << MSC_INTR_RMASF_SH);
-#if DEBUG
-			show_mapping_ctx(0,context,vaddr);
-#endif
-			msc_blocked++;
-			async_fault(vaddr,1,tsk,async_callback);
-			return;
-		}
-	}
-	
-#if DEBUG
-	printk("CID(%d) mas write fault context=%x vaddr=%x\n",
-	       mpp_cid(),context,vaddr);
-#endif
-	
-	fail_write(context,MSC_INTR_RMASF_SH,vaddr);
-}
-
-
-static inline void msc_read_fault(void)
-{
-	unsigned context = MSC_IN(MSC_SMASREG) >> 20;
-	unsigned vaddr = MSC_IN(MSC_SMASTWP)<<12;
-		
-	if (context == SYSTEM_CONTEXT) {
-		fail_read(context,MSC_INTR_SMASF_SH,vaddr);
-		show_mapping_ctx(0,context,vaddr);
-		printk("ERROR: system read fault at %x\n",vaddr);
-		return;
-	}
-
-	if (MPP_IS_PAR_CTX(context)) {
-		int tsk = MPP_CTX_TO_TASK(context);
-		
-		if (vaddr - MSC_REM_SIGNAL < _NSIG*PAGE_SIZE) {
-			fail_read(context,MSC_INTR_SMASF_SH,vaddr);
-			return;
-		}
-
-		if (valid_task(task[tsk]) && task[tsk]->ringbuf) {
-			MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_SMASF_SH);
-			intr_mask |= (AP_INTR_REQ << MSC_INTR_SMASF_SH);
-			msc_blocked++;
-			async_fault(vaddr,0,tsk,async_callback);
-			return;
-		}
-	}
-	
-#if DEBUG
-	printk("CID(%d) mas read fault context=%x vaddr=%x\n",
-	       mpp_cid(),context,vaddr);
-#endif
-	
-	fail_read(context,MSC_INTR_SMASF_SH,vaddr);
-}
-	
-
-
-static void msc_interrupt_9(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned long flags;
-	unsigned intr, cnt, r;
-
-	save_flags(flags); cli();
-
-	if (intr_counter++ == INTR_LIMIT) {
-		mask_all_interrupts();
-		printk("too many MSC interrupts\n");
-		restore_flags(flags); 
-		return;
-	}
-
-	intr = MSC_IN(MSC_INTR) & ~intr_mask;    
-
-#if DEBUG
-	printk("CID(%d) msc_interrupt_9: intr = %x\n", mpp_cid(), intr);
-#endif
-	
-	if (intr & (AP_INTR_REQ << MSC_INTR_RMASF_SH)) {
-		msc_write_fault();
-	}
-	
-	if (intr & (AP_INTR_REQ << MSC_INTR_SMASF_SH)) {
-		msc_read_fault();
-	}
-
-	if (intr & (AP_INTR_REQ << MSC_INTR_RMASE_SH)) {
-		printk("recv mas error interrupt (write)\n");
-		printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL));
-		printk("rmasadr = %x %x\n", MSC_IN(MSC_RMASADR),
-		       MSC_IN(MSC_RMASADR + 4));
-		printk("rmastwp = %x\n", MSC_IN(MSC_RMASTWP));
-		printk("rmasreg = %x\n", MSC_IN(MSC_RMASREG));
-		r = MSC_IN(MSC_RMASREG);
-		if ((r & MSC_MASR_AVIO) || (r & MSC_MASR_CMD) != MSC_MASR_CMD_XFER)
-			/* throw away the rest of the incoming data */
-			MSC_OUT(MSC_RHDERRPROC, 0);
-		/* clear the interrupt */
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_RMASE_SH);
-	}
-	
-	if (intr & (AP_INTR_REQ << MSC_INTR_SMASE_SH)) {
-		printk("send mas error interrupt (read)\n");
-		printk("masctrl = %x\n", MSC_IN(MSC_MASCTRL));
-		printk("smasadr = %x %x\n", MSC_IN(MSC_SMASADR),
-		       MSC_IN(MSC_SMASADR + 4));
-		printk("smascnt = %x\n", MSC_IN(MSC_SMASCNT));
-		printk("smastwp = %x\n", MSC_IN(MSC_SMASTWP));
-		printk("smasreg = %x\n", MSC_IN(MSC_SMASREG));
-		/* supply dummy data */
-		cnt = MSC_IN(MSC_SMASCNT);
-		switch (MSC_IN(MSC_SMASREG) & MSC_MASR_CMD) {
-		case MSC_MASR_CMD_XFER:
-			MSC_OUT(MSC_HDGERRPROC, (EXTFIELD(cnt, MSC_SMCT_MCNT)
-						 + EXTFIELD(cnt, MSC_SMCT_ICNT)));
-			break;
-			/* case remote read: */
-		case MSC_MASR_CMD_FOP:
-		case MSC_MASR_CMD_CSI:
-			MSC_OUT(MSC_HDGERRPROC, 1);
-			break;
-		}
-		/* clear interrupt */
-		MSC_OUT(MSC_INTR, AP_CLR_INTR_REQ << MSC_INTR_SMASF_SH);
-	}
-	
-	restore_flags(flags);
-}
-
-/*
- * remove access to a tasks ring buffer
- */
-void msc_unset_ringbuf(int i)
-{
-	int ctx = MSC_IN(ringbufs[i].rbmmode) & CTX_MASK;
-	int tsk = MPP_CTX_TO_TASK(ctx);
-	struct ringbuf_struct *rbuf;
-  
-#if DEBUG
-	printk("msc_unset_ringbuf(%d) %x\n",i,ctx);
-#endif
-
-	MSC_OUT(ringbufs[i].rbmmode,NULL_CONTEXT);
-	if (ctx == SYSTEM_CONTEXT) { 
-		rbuf = &system_ringbuf;
-	} else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) && 
-		   valid_task(task[tsk]) && task[tsk]->ringbuf) {
-		rbuf = task[tsk]->ringbuf;
-	} else if (ctx != NULL_CONTEXT && MPP_IS_PAR_CTX(ctx) &&
-		   valid_task(task[tsk]) && task[tsk]->aplib) {
-		rbuf = &system_ringbuf;
-	} else {
-		rbuf = &dummy_ringbuf;
-	}
-
-	rbuf->write_ptr = MSC_IN(ringbufs[i].rbmbwp);
-}
-
-static void msc_update_read_ptr(int context,int overflow)
-{
-	int i;
-	unsigned new_read_ptr;
-
-	for (i=0;i<NR_RBUFS;i++) {
-		if ((MSC_IN(ringbufs[i].rbmmode)&CTX_MASK) == context) break;
-	}
-	if (i == NR_RBUFS) {
-		printk("didn't find context %d in msc_update_read_ptr()\n",
-		       context);
-		return;
-	}
-
-	if (context == SYSTEM_CONTEXT) {
-		tnet_check_completion();
-		if (overflow && MSC_IN(ringbufs[i].rbmrp) == system_read_ptr)
-			printk("system ringbuffer overflow\n");
-		new_read_ptr = system_read_ptr;
-	} else if (MPP_IS_PAR_CTX(context) && 
-		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
-		   task[MPP_CTX_TO_TASK(context)]->ringbuf) {
-		struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)];
-		struct _kernel_cap_shared *_kernel;
-		unsigned soft_read_ptr;
-		unsigned octx;
-
-		octx = apmmu_get_context();
-		if (octx != context) 
-			apmmu_set_context(context);
-		_kernel = (struct _kernel_cap_shared *)(RBUF_VBASE + RBUF_SHARED_PAGE_OFF);
-		soft_read_ptr = _kernel->rbuf_read_ptr;
-		if (octx != context) 
-			apmmu_set_context(octx);
-
-		if (overflow && MSC_IN(ringbufs[i].rbmrp) == soft_read_ptr) {
-			/* send them a SIGLOST and wipe their ring buffer */
-			printk("ring buffer overflow for %s ctx=%x\n",
-			       tsk->comm,context);
-			send_sig(SIGLOST,tsk,1);
-			soft_read_ptr--;
-		}
-		new_read_ptr = soft_read_ptr;
-	} else if (MPP_IS_PAR_CTX(context) && 
-		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
-		   task[MPP_CTX_TO_TASK(context)]->aplib) {
-		tnet_check_completion();
-		if (overflow && MSC_IN(ringbufs[i].rbmrp) == system_read_ptr)
-                        printk("system ringbuffer overflow\n");
-                new_read_ptr = system_read_ptr;		
-	} else {
-		dummy_read_ptr = MSC_IN(ringbufs[i].rbmrp) - 1;
-		new_read_ptr = dummy_read_ptr - 1;
-#if DEBUG
-		if (overflow)
-			printk("reset dummy ring buffer for context %x\n",
-			       context);
-#endif
-	}
-
-
-	MSC_OUT(ringbufs[i].rbmrp,new_read_ptr);
-}
-
-/*
- * give a task one of the system ring buffers 
- * this is called on a context miss interrupt, so we can assume that
- * the tasks context is not currently set in one of the ringbufs
- */
-static void msc_set_ringbuf(int context)
-{
-	int i;
-	int ctx;
-	int mode;
-	unsigned write_ptr;
-	static unsigned next_ctx = 0;
-	struct ringbuf_struct *rbuf;
-
-	if (context == SYSTEM_CONTEXT) {
-		rbuf = &system_ringbuf;
-	} else if (MPP_IS_PAR_CTX(context) && 
-		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
-		   task[MPP_CTX_TO_TASK(context)]->ringbuf) {
-		struct task_struct *tsk = task[MPP_CTX_TO_TASK(context)];
-		rbuf = tsk->ringbuf;
-	} else if (MPP_IS_PAR_CTX(context) && 
-		   valid_task(task[MPP_CTX_TO_TASK(context)]) &&
-		   task[MPP_CTX_TO_TASK(context)]->aplib) {
-		rbuf = &system_ringbuf;
-	} else {
-		/* use the dummy ring buffer */
-		rbuf = &dummy_ringbuf;
-	}
-
-	for (i=0;i<NR_RBUFS; i++) {
-		ctx = MSC_IN(ringbufs[i].rbmmode)&CTX_MASK;
-		if (ctx == NULL_CONTEXT) break;
-	}
-	if (i == NR_RBUFS) {
-		i = next_ctx;
-		next_ctx = (i+1)%NR_RBUFS;
-	}
-
-	ctx = MSC_IN(ringbufs[i].rbmmode)&CTX_MASK;
-	if (ctx != NULL_CONTEXT) msc_unset_ringbuf(i);
-
-	write_ptr = rbuf->write_ptr;
-	mode = (rbuf->order - 5) >> 1;
-	
-	MSC_OUT(ringbufs[i].rbmmode,context | (mode << 12));
-	MSC_OUT(ringbufs[i].rbmbwp,write_ptr);
-
-	if (rbuf == &system_ringbuf) {
-		MSC_OUT(ringbufs[i].rbmrp,system_read_ptr);
-	} else {
-		msc_update_read_ptr(context,0);
-	}
-	
-#if DEBUG
-	printk("CID(%d) mapped ringbuf for context %d in slot %d\n",
-	       mpp_cid(),context,i);
-#endif
-}
-
-
-/*
- * this is called when a task exits
-*/
-void exit_msc(struct task_struct *tsk)
-{
-	int i;
-
-	if (!MPP_IS_PAR_TASK(tsk->taskid))
-		return;
-
-#if DEBUG
-	printk("exit_msc(%d) ctx=%d\n",tsk->taskid,tsk->mm->context);
-#endif
-
-	for (i=0;i<NR_RBUFS; i++) {
-		int ctx = MSC_IN(ringbufs[i].rbmmode)&CTX_MASK;
-		if (ctx == MPP_TASK_TO_CTX(tsk->taskid))
-			msc_unset_ringbuf(i);
-	}
-	msc_switch_from_check(tsk);
-
-	/* stop it receiving new-style messages */
-	tsk->aplib = NULL;
-
-	exit_ringbuf(tsk);
-}
-
-
-static void msc_sq_pause(void)
-{
-	MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) | MSC_SQC_PAUSE);
-	while (!(MSC_IN(MSC_SQCTRL) & MSC_SQC_STABLE)) /* wait for stable bit */ ;
-}
-
-static void msc_sq_resume(void)
-{
-	MSC_OUT(MSC_SQCTRL,MSC_IN(MSC_SQCTRL) & ~MSC_SQC_PAUSE);
-}
-
-static void msc_switch_from_check(struct task_struct *tsk)
-{
-	int user_count;
-	unsigned flags;
-	struct ringbuf_struct *rbuf = NULL;
-	int octx, ctx;
-
-	if (valid_task(tsk) && tsk->ringbuf)
-		rbuf = tsk->ringbuf;
-	
-	/* it doesn't seem obvious why this field should contain count+1,
-	   but it does */
-	user_count = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1;
-	
-	/* check if the user queue count is != 0 */
-	if (user_count == 0) return;
-
-	if (!rbuf)
-		printk("switching from dead task\n");
-	
-#if 1
-	printk("saving %d words MSC_QWORDCNT=%x\n",
-	       user_count,MSC_IN(MSC_QWORDCNT));
-#endif
-	
-	/* bugger - we have to do some messy work */
-	save_flags(flags); cli();
-
-	ctx = MPP_TASK_TO_CTX(tsk->taskid);
-	octx = apmmu_get_context();
-	if (octx != ctx)
-		apmmu_set_context(ctx);
-
-	msc_sq_pause();
-	
-	/* remember the expected length of the command - usually (always?) 8 */
-	if (rbuf)
-		rbuf->frag_len = EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRLEN);
-	
-	/* pull words from the overflow first */
-	if (MSC_IN(MSC_SQCTRL) & MSC_SQC_USERF) {
-		/* we have overflowed */
-		struct qof_elt *qof_wp = qof_base + 
-			(EXTFIELD(MSC_IN(MSC_QBMPTR), MSC_QBMP_WP) & ((QOF_SIZE - 1) >> 3));
-		while (qof_wp != qof_rp && user_count) {
-			qof_wp--;
-			/* only grab elements in the user queue */
-			if (qof_wp->info && log2tbl[EXTFIELD(qof_wp->info, QOF_QUEUE)] == 2) {
-				if (qof_wp->info & 1) {
-					printk("MSC: end bit set - yikes!\n");
-				}
-				qof_wp->info = 0;
-				if (rbuf) {
-					rbuf->sq_fragment[--user_count] = qof_wp->data;
-					rbuf->frag_count++;
-				}
-				if (qof_wp < qof_new)
-					qof_present[2]--;
-			}
-		}
-#if DEBUG
-		if (rbuf)
-			printk("pulled %d elements from overflow (%d left)\n",
-			       rbuf->frag_count,user_count);
-#endif
-	}
-	
-	/* then pull words direct from the msc ram */
-	if (user_count) {
-		int wp = EXTFIELD(MSC_IN(MSC_SQPTR2),MSC_SQP_WP);
-		int i;
-		wp -= user_count;
-		if (wp < 0) wp += send_queues[2].size;
-		
-		for (i=0;i<user_count;i++) {
-			int wp2 = (wp + i)%send_queues[2].size;
-			if (rbuf)
-				rbuf->sq_fragment[i + rbuf->frag_count] = 
-					MSC_IN(MSC_SQRAM + (send_queues[2].base + wp2)*8);
-		}
-		
-		if (rbuf)
-			rbuf->frag_count += user_count;
-		
-		MSC_OUT(MSC_SQPTR2,INSFIELD(MSC_IN(MSC_SQPTR2),wp,MSC_SQP_WP));
-#if DEBUG
-		printk("saved %d words from msc ram\n",rbuf->frag_count);
-#endif
-	}
-  
-	/* reset the user count to 1 */
-	MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),1,MSC_QWDC_USRCNT));
-	
-	msc_sq_resume();
-
-	if (octx != ctx)
-		apmmu_set_context(octx);
-
-	restore_flags(flags);
-}
-
-static void msc_switch_to_check(struct task_struct *tsk)
-{
-	int i;
-	unsigned flags;
-	int octx, ctx;
-	
-	if (!valid_task(tsk) || !tsk->ringbuf)
-		return;
-
-	save_flags(flags); cli();
-
-	
-	ctx = MPP_TASK_TO_CTX(tsk->taskid);
-	octx = apmmu_get_context();
-	if (octx != ctx)
-		apmmu_set_context(ctx);
-
-	/* if the task we are switching to has no saved words then 
-	   we're finished */
-	if (tsk->ringbuf->frag_count == 0) {
-		if (octx != ctx)
-			apmmu_set_context(octx);
-		restore_flags(flags);
-		return;
-	}
-	
-
-#if 1
-	printk("frag fill MSC_QWORDCNT=%x frag_count=%d\n",
-	       MSC_IN(MSC_QWORDCNT),tsk->ringbuf->frag_count);
-#endif	
-	
-	/* reset the user length */
-	MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),
-				      tsk->ringbuf->frag_len,
-				      MSC_QWDC_USRLEN));
-	
-	/* push the words into the direct queue */
-	for (i=0;i<tsk->ringbuf->frag_count;i++)
-		MSC_OUT(MSC_USER_DIRECT,tsk->ringbuf->sq_fragment[i]);
-	
-	/* reset the user count */
-	MSC_OUT(MSC_QWORDCNT,INSFIELD(MSC_IN(MSC_QWORDCNT),
-				      1+tsk->ringbuf->frag_count,
-				      MSC_QWDC_USRCNT));
-	
-#if DEBUG
-	printk("frag fill done MSC_QWORDCNT=%x\n",
-	       MSC_IN(MSC_QWORDCNT));
-#endif
-	
-	tsk->ringbuf->frag_count = 0;
-	tsk->ringbuf->frag_len = 0;
-	if (octx != ctx)
-		apmmu_set_context(octx);
-	restore_flags(flags);
-}
-
-
-
-void msc_switch_check(struct task_struct *tsk)
-{
-	static int last_task = 0;
-
-	if (last_task == tsk->taskid) return;
-
-	if (MPP_IS_PAR_TASK(last_task))
-		msc_switch_from_check(task[last_task]);
-
-	msc_switch_to_check(tsk);
-	
-	last_task = tsk->taskid;
-}
-
-/* we want to try to avoid task switching while there are partial commands
-   in the send queues */
-int msc_switch_ok(void)
-{
-	if ((EXTFIELD(MSC_IN(MSC_QWORDCNT),MSC_QWDC_USRCNT) - 1))
-		return 0;
-
-	return 1;
-}
-
-/*
- * print out the state of the msc
-*/
-static void msc_status(void)
-{
-	int i;
-
-	printk("MSC_SQCTRL=%x\n",MSC_IN(MSC_SQCTRL));
-  
-	for (i=0;i<5;i++)
-		printk("MSC_SQPTR%d=%x\n",i,MSC_IN(MSC_SQPTR0 + 8*i));  
-	printk("MSC_OPTADR=%x\n",MSC_IN(MSC_OPTADR));  
-	printk("MSC_MASCTRL=%x\n", MSC_IN(MSC_MASCTRL));
-	printk("MSC_SMASADR=%x_%x\n", MSC_IN(MSC_SMASADR),MSC_IN(MSC_SMASADR + 4));
-	printk("MSC_RMASADR=%x_%x\n", MSC_IN(MSC_RMASADR),MSC_IN(MSC_RMASADR + 4));
-	printk("MSC_PID=%x\n",MSC_IN(MSC_PID));
-	
-	printk("MSC_QWORDCNT=%x\n",MSC_IN(MSC_QWORDCNT));
-	
-	printk("MSC_INTR=%x\n",MSC_IN(MSC_INTR));
-	printk("MSC_CIDRANGE=%x\n",MSC_IN(MSC_CIDRANGE));
-	printk("MSC_QBMPTR=%x\n",MSC_IN(MSC_QBMPTR));
-	printk("MSC_SMASTWP=%x\n", MSC_IN(MSC_SMASTWP));
-	printk("MSC_RMASTWP=%x\n", MSC_IN(MSC_RMASTWP));
-	printk("MSC_SMASREG=%x\n", MSC_IN(MSC_SMASREG));
-	printk("MSC_RMASREG=%x\n", MSC_IN(MSC_RMASREG));
-	printk("MSC_SMASCNT=%x\n", MSC_IN(MSC_SMASCNT));
-	printk("MSC_IRL=%x\n", MSC_IN(MSC_IRL));
-	printk("MSC_SIMMCHK=%x\n", MSC_IN(MSC_SIMMCHK));
-	
-	for (i=0;i<3;i++) {
-		printk("RBMBWP%d=%x\n",i,MSC_IN(ringbufs[i].rbmbwp));
-		printk("RBMMODE%d=%x\n",i,MSC_IN(ringbufs[i].rbmmode));
-		printk("RBMRP%d=%x\n",i,MSC_IN(ringbufs[i].rbmrp));
-	}
-	
-	printk("DMA_GEN=%x\n",MSC_IN(DMA_GEN));
-
-	printk("qbm_full_counter=%d\n",qbm_full_counter);
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/sync.c linux/arch/sparc/ap1000/sync.c
--- v2.3.41/linux/arch/sparc/ap1000/sync.c	Tue Sep  7 12:14:06 1999
+++ linux/arch/sparc/ap1000/sync.c	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* sync functions using the Tnet */
-
-#include <asm/ap1000/apreg.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/threads.h>
-
-extern int cap_cid0;
-extern unsigned _ncel, _ncelx, _ncely, _cid;
-
-static volatile int sync_flags[MPP_NUM_TASKS];
-
-
-int ap_sync(int numcells, int *phys_map)
-{
-	int basecell;
-	int i,err;
-	int tsk = current->taskid;
-	
-	if (numcells < 2) return 0;
-
-	if (!MPP_IS_PAR_TASK(tsk)) {
-		printk("nonparallel task %d called ap_sync\n",tsk);
-		return 0;
-	}
-	tsk -= MPP_TASK_BASE;
-	
-	basecell = phys_map[0];
-	if (cap_cid0 == basecell) {    
-		if ((err=wait_on_int(&sync_flags[tsk],numcells-1,5)))
-			return err;
-		sync_flags[tsk] = 0;
-		if (numcells == _ncel) {
-			ap_bput(0,0,0,&sync_flags[tsk],0);
-		} else {
-			for (i=1;i<numcells;i++)
-				ap_put(phys_map[i],0,0,0,&sync_flags[tsk],0);
-		}
-		return 0;
-	}
-	
-	ap_put(basecell,0,0,0,&sync_flags[tsk],0);
-	if ((err=wait_on_int(&sync_flags[tsk],1,5)))
-		return err;
-	sync_flags[tsk] = 0;
-	return 0;
-}
-
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/timer.c linux/arch/sparc/ap1000/timer.c
--- v2.3.41/linux/arch/sparc/ap1000/timer.c	Tue Aug  4 23:40:54 1998
+++ linux/arch/sparc/ap1000/timer.c	Wed Dec 31 16:00:00 1969
@@ -1,125 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* routines to control the AP1000 timer chip */   
-
-#include <linux/time.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/irq.h>
-
-#define INIT_TIM1	(781250/HZ)
-#define INIT_TIM0	(781250/(10*HZ))
-
-static unsigned long last_freerun;
-
-unsigned ap_freerun(void)
-{
-	return *((volatile unsigned long *)(MC_FREERUN + 4));
-}
-
-void ap_clear_clock_irq(void)
-{
-	MC_OUT(MC_INTR, AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH);
-	last_freerun = *((unsigned long *)(MC_FREERUN + 4));
-	tnet_check_completion();
-#if 1
-	if ((((unsigned)jiffies) % (HZ/4)) == 0) {
-		msc_timer();
-		ap_xor_led(1);
-		bif_timer();
-		ap_dbg_flush();
-#if 0
-		bif_led_status();
-#endif
-	}
-#endif
-}
-
-
-void ap_gettimeofday(struct timeval *xt)
-{
-	unsigned long d;
-	unsigned v;
-	unsigned long new_freerun;
-
-	/* this is in 80ns units - we only use the low 32 bits 
-	   as 5mins is plenty for this stuff */
-	d = new_freerun = *((unsigned long *)(MC_FREERUN + 4)); 
-
-	if (d < last_freerun) {
-		/* wraparound */
-		d += ((~0) - last_freerun);
-	} else {
-		d -= last_freerun;
-	}
-
-	/* convert to microseconds */
-	v = ((d&0xffffff)*10)/125;
-	
-	/* only want microseconds/HZ */
-	v = v%(1000000/HZ);
-	
-	xt->tv_usec += v;
-
-	last_freerun = new_freerun;
-}
-
-static void profile_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
-  if (prof_buffer && current->pid) {
-    extern int _stext;
-    unsigned long ip = instruction_pointer(regs);
-    ip -= (unsigned long) &_stext;
-    ip >>= prof_shift;
-    if (ip < prof_len)
-      prof_buffer[ip]++;
-  }  
-  MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH);
-}
-
-void ap_profile_init(void)
-{
-  if (prof_shift) {
-    printk("Initialising profiling with prof_shift=%d\n",(int)prof_shift);
-    MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM0_SH);
-    MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM0_SH);
-  }
-}
-
-void ap_init_timers(void)
-{
-	extern void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs);
-	unsigned flags;
-
-	printk("Initialising ap1000 timer\n");
-
-	save_flags(flags); cli();
-	
-	request_irq(APTIM1_IRQ,
-		    timer_interrupt,
-		    (SA_INTERRUPT | SA_STATIC_ALLOC),
-		    "timer", NULL);
-
-	request_irq(APTIM0_IRQ,
-		    profile_interrupt,
-		    (SA_INTERRUPT | SA_STATIC_ALLOC),
-		    "profile", NULL);
-	
-	ap_clear_clock_irq();
-	
-	MC_OUT(MC_ITIMER0,INIT_TIM0);
-	MC_OUT(MC_ITIMER1,INIT_TIM1);
-	MC_OUT(MC_INTR,AP_CLR_INTR_REQ << MC_INTR_ITIM1_SH);
-	MC_OUT(MC_INTR,AP_CLR_INTR_MASK << MC_INTR_ITIM1_SH);
-	MC_OUT(MC_INTR,AP_SET_INTR_MASK << MC_INTR_ITIM0_SH);
-	restore_flags(flags); 
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/tnet.c linux/arch/sparc/ap1000/tnet.c
--- v2.3.41/linux/arch/sparc/ap1000/tnet.c	Tue Aug  4 16:03:34 1998
+++ linux/arch/sparc/ap1000/tnet.c	Wed Dec 31 16:00:00 1969
@@ -1,708 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* routines to control the AP1000 Tnet interface */
-
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/aplib.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <asm/pgtable.h>
-#include <asm/pgtsrmmu.h>
-#include <stdarg.h>
-#include <linux/skbuff.h>
-
-
-/* message types for system messages */
-#define TNET_IP         0
-#define TNET_IP_SMALL   1
-#define TNET_RPC        2
-
-static struct {
-	int errors;
-	int alloc_errors;
-	int bytes_received;
-	int bytes_sent;
-	int packets_received;
-	int packets_sent;
-	int small_packets_received;
-	int small_packets_sent;
-} tnet_stats;
-
-extern int cap_cid0;
-extern int cap_ncel0;
-static u_long xy_global_head;
-
-extern unsigned _ncel, _ncelx, _ncely, _cid, _cidx, _cidy;
-
-extern struct ringbuf_struct system_ringbuf;
-extern u_long system_read_ptr;
-
-u_long system_recv_flag = 0;
-static u_long system_recv_count = 0;
-
-int *tnet_rel_cid_table;
-
-static int dummy=1;
-
-#define TNET_IP_THRESHOLD 100
-
-void tnet_check_completion(void);
-static void reschedule(void);
-static u_long tnet_add_completion(void (*fn)(int a1,...), 
-				  int a1,int a2);
-static void tnet_info(void);
-
-static struct {
-  int shift;
-  void (*fn)(void);
-} iports[4] = {
-  {MC_INTP_0_SH,tnet_check_completion},
-  {MC_INTP_1_SH,reschedule},
-  {MC_INTP_2_SH,NULL},
-  {MC_INTP_3_SH,NULL}};
-
-static inline int rel_cid(unsigned dst)
-{  
-	unsigned dstx, dsty;
-	unsigned dx,dy;
-
-	if (dst == _cid) return 0;
-
-	dstx = dst % _ncelx;
-	dsty = dst / _ncelx;
-	if (dstx >= _cidx)
-		dx = dstx - _cidx;
-	else
-		dx = (_ncelx - _cidx) + dstx;
-	
-	if (dsty >= _cidy)
-		dy = dsty - _cidy;
-	else
-		dy = (_ncely - _cidy) + dsty;
-	
-	return (dx<<8) | dy;
-}
-
-#define SAVE_PID() \
-  unsigned long flags; \
-  int saved_pid; \
-  save_flags(flags); cli(); \
-  saved_pid = MSC_IN(MSC_PID); \
-  MSC_OUT(MSC_PID,SYSTEM_CONTEXT);
-
-#define RESTORE_PID() \
-  MSC_OUT(MSC_PID,saved_pid); \
-  restore_flags(flags);
-
-
-void ap_put(int dest_cell,u_long local_addr,int size,
-	    u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
-  volatile u_long *entry;
-  SAVE_PID();
-    
-  entry = (volatile u_long *)MSC_PUT_QUEUE_S;
-
-  *entry = tnet_rel_cid_table[dest_cell];
-  *entry = ((size+3) >> 2); 
-  *entry = (u_long)remote_addr;
-  *entry = 0;
-  *entry = (u_long)dest_flag;
-  *entry = (u_long)local_flag;
-  *entry = (u_long)local_addr;
-  *entry = 0;
-  RESTORE_PID();
-}
-
-/* remote_addr is physical 
-   local address is virtual 
-   both flags are virtual */
-void ap_phys_put(int dest_cell,u_long local_addr,int size,
-		 u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
-  volatile u_long *entry;
-  SAVE_PID();
-
-  entry = (volatile u_long *)MSC_CPUT_QUEUE_S;
-
-  *entry = tnet_rel_cid_table[dest_cell];
-  *entry = ((size+3) >> 2); 
-  *entry = (u_long)remote_addr;
-  *entry = 0;
-  *entry = (u_long)dest_flag;
-  *entry = (u_long)local_flag;
-  *entry = (u_long)local_addr;
-  *entry = 0;
-  RESTORE_PID();
-}
-
-
-/* broadcast put - yeah! */
-void ap_bput(u_long local_addr,int size,
-	     u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
-  volatile u_long *entry = (volatile u_long *)MSC_XYG_QUEUE_S;
-  SAVE_PID();
-
-  *entry = xy_global_head;
-  *entry = ((size+3) >> 2);
-  *entry = (u_long)remote_addr;
-  *entry = 0;
-  *entry = (u_long)dest_flag;
-  *entry = (u_long)local_flag;
-  *entry = (u_long)local_addr;
-  *entry = 0;
-  RESTORE_PID();
-}
-
-
-/* remote_addr is physical */
-void ap_phys_bput(u_long local_addr,int size,
-		  u_long remote_addr,u_long dest_flag,u_long local_flag)
-{
-  volatile u_long *entry = (volatile u_long *)MSC_CXYG_QUEUE_S;
-  SAVE_PID();
-
-  *entry = xy_global_head;
-  *entry = ((size+3) >> 2);
-  *entry = (u_long)remote_addr;
-  *entry = 0;
-  *entry = (u_long)dest_flag;
-  *entry = (u_long)local_flag;
-  *entry = (u_long)local_addr;
-  *entry = 0;
-  RESTORE_PID();
-}
-
-
-
-void ap_get(int dest_cell,u_long local_addr,int size,
-	    u_long remote_addr,u_long local_flag,u_long dest_flag)
-{
-  volatile u_long *entry;
-  SAVE_PID();
-    
-  entry = (u_long *)MSC_GET_QUEUE_S;
-
-  *entry = tnet_rel_cid_table[dest_cell];
-  *entry = (size+3) >> 2;           /* byte --> word */
-  *entry = (u_long)local_addr;
-  *entry = 0;
-  *entry = (u_long)local_flag;
-  *entry = (u_long)dest_flag;
-  *entry = (u_long)remote_addr;
-  *entry = 0;    
-  RESTORE_PID();
-}
-
-
-/* local_addr is physical 
-   remote_addr is virtual
-   both flags are virtual
-*/
-void ap_phys_get(int dest_cell,u_long local_addr,int size,
-		 u_long remote_addr,u_long local_flag,u_long dest_flag)
-{
-  volatile u_long *entry;
-  SAVE_PID();
-    
-  entry = (u_long *)MSC_CGET_QUEUE_S;
-
-  *entry = tnet_rel_cid_table[dest_cell];
-  *entry = (size+3) >> 2;           /* byte --> word */
-  *entry = (u_long)local_addr;
-  *entry = 0;
-  *entry = (u_long)local_flag;
-  *entry = (u_long)dest_flag;
-  *entry = (u_long)remote_addr;
-  *entry = 0;    
-  RESTORE_PID();
-}
-
-
-/*
- * copy a message from the ringbuffer - being careful of wraparound
-*/
-static inline void tnet_copyin(unsigned *dest,unsigned *src,int size)
-{
-	unsigned *limit = (unsigned *)system_ringbuf.ringbuf + 
-		(SYSTEM_RINGBUF_SIZE>>2);
-	int size1 = limit - src;
-
-	if (size < size1)
-		size1 = size;
-
-	size -= size1;
-	while (size1--) {
-		*dest++ = *src++;
-	}
-	src = system_ringbuf.ringbuf;
-	while (size--) {
-		*dest++ = *src++;
-	}
-}
-
-
-/*
-  put some data into a tasks ringbuffer. size is in words.
-  */
-static inline void memcpy_to_rbuf(unsigned tid,unsigned *msgp,unsigned size)
-{
-	struct aplib_struct *aplib;
-	unsigned octx, ctx;
-	struct task_struct *tsk;
-	unsigned room;
-
-	tsk = task[tid];
-	if (!tsk || !tsk->aplib)
-		return;
-
-	octx = srmmu_get_context();
-	ctx = MPP_TASK_TO_CTX(tid);
-	if (octx != ctx)
-		srmmu_set_context(ctx);
-	aplib = tsk->aplib;
-
-	if (aplib->write_pointer < aplib->read_pointer) 
-		room = aplib->read_pointer - (aplib->write_pointer+1);
-	else
-		room = aplib->ringbuf_size - 
-			((aplib->write_pointer+1)-aplib->read_pointer);
-
-	if (room < size) {
-		send_sig(SIGLOST,tsk,1);		
-		goto finished;
-	}
-
-	tnet_copyin(&aplib->ringbuf[aplib->write_pointer], msgp, size);
-
-	aplib->write_pointer += size;
-	if (aplib->write_pointer >= aplib->ringbuf_size)
-		aplib->write_pointer -= aplib->ringbuf_size;
-
-	aplib->rbuf_flag1++;
-
-finished:
-	if (octx != ctx)
-		srmmu_set_context(octx);
-}
-
-
-
-/* a aplib message has arrived on the system message queue - process
-   it immediately and return the number of bytes taken by the message in
-   the system ringbuffer 
-
-   Note that this function may be called from interrupt level
-   */
-static inline void aplib_system_recv(unsigned *msgp)
-{
-	unsigned tag = msgp[1]>>28;
-	unsigned size, tid;
-
-	if (tag == RBUF_BIGSEND) {
-		aplib_bigrecv(msgp);
-		return;
-	}
-
-	size = (msgp[0]&0xFFFFF);
-	tid = (msgp[1]&0x3FF);
-
-	memcpy_to_rbuf(tid,msgp,size+2);
-}
-
-
-void tnet_ip_complete(struct sk_buff *skb,int from)
-{  
-#if IP_DEBUG
-	char *data = skb->data;
-	int i;
-	printk("CID(%d) tnet ip complete from %d\n",_cid,from);
-
-	for (i=0;i<skb->len;i+=4)
-		printk("(%08x)%c",*(int *)(data+i),i==32?'\n':' ');
-	printk("\n");
-#endif
-	/* ap_phys_put(from,(u_long)&dummy,4,MC_INTP_0,0,0); */
-	bif_rx(skb);
-	tnet_stats.bytes_received += skb->len;
-	tnet_stats.packets_received++;
-}
-
-
-static void tnet_ip_recv(int cid,u_long *info)
-{
-	u_long flag;
-	u_long ipsize = info[1];
-	u_long remote_addr = info[0];
-	u_long remote_flag = info[2];
-	struct sk_buff *skb = dev_alloc_skb(ipsize+8);
-	char *p;
-
-	if (!skb) {
-		ap_put(cid,0,0,0,remote_flag,0);
-		ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0);
-		tnet_stats.alloc_errors++;
-		return;
-	}
-
-	skb_reserve(skb,8); /* align on 16 byte boundary */
-
-	flag = tnet_add_completion(tnet_ip_complete,(int)skb,(int)cid);
-
-	p = (char *)skb_put(skb,ipsize);
-#if 0
-{
-	static unsigned count=0;
-	if (count%500 == 0)
-		printk("CID(%d) fetching %d bytes from %x to %x\n",
-		       _cid,ipsize,remote_addr,p);
-	count++;
-}
-#endif
-	ap_get(cid,p,ipsize,remote_addr,flag,remote_flag);
-	ap_phys_get(cid,MC_INTP_0,4,(u_long)&dummy,0,0);
-#if IP_DEBUG
-	printk("CID(%d) ip packet of length %ld from %ld\n",_cid,ipsize,cid);
-#endif
-}
-
-
-static void tnet_ip_recv_small(u_long *data,int size)
-{
-	struct sk_buff *skb = dev_alloc_skb(size+8);
-	if (skb) {
-		skb_reserve(skb,8);
-		tnet_copyin((unsigned *)skb_put(skb,size),(unsigned *)data,(size+3)>>2);
-		bif_rx(skb);
-		tnet_stats.bytes_received += size;
-		tnet_stats.packets_received++;
-		tnet_stats.small_packets_received++;
-	} else {
-		tnet_stats.alloc_errors++;
-	}
-}
-
-
-/* we've got an RPC from a remote cell */
-static void tnet_rpc_recv(u_long *data,int size)
-{
-	struct fnp {
-		void (*fn)();
-	} fnp;
-	fnp = *(struct fnp *)data;
-	fnp.fn(data,size);
-}
-
-/*
- * receive messages from the system ringbuffer. We don't bother with
- * all the niceities that are done in user space, we just always
- * process the messages in order 
- */
-static inline void tnet_recv(void)
-{
-	unsigned flags;
-	u_long from,*data,fix,align,size1,size,type;
-
-	if (system_recv_flag == system_recv_count) 
-		return;
-
-	save_flags(flags); cli();
-	while (system_recv_flag != system_recv_count) {
-		u_long read_ptr = 
-			(system_read_ptr + 1) % (SYSTEM_RINGBUF_SIZE>>5);  
-		u_long *msgp = 
-			((u_long *)system_ringbuf.ringbuf) + (read_ptr<<3);
-		u_long tag = (msgp[1]>>28) & 0xF;
-		size1 = (msgp[0]&0xFFFFF)<<2;
-
-		/* move our read pointer past this message */
-		system_read_ptr = (system_read_ptr + 
-				   ((size1+8+31)>>5))%(SYSTEM_RINGBUF_SIZE>>5);
-		system_recv_count++;		
-
-
-		if (tag != RBUF_SYSTEM) {
-			aplib_system_recv(msgp);
-			continue;
-		} 
-
-		from = msgp[0] >> 22;
-		data = msgp+2;
-		fix = (msgp[0]>>20)&3;
-		align = (msgp[1]>>26)&3;
-		size = ((size1 - align) & ~3) | fix;
-		type = (msgp[1]&0xFF);
-
-		switch (type) {
-		case TNET_IP:
-			tnet_ip_recv(from,data);
-			break;
-			
-		case TNET_IP_SMALL:
-			tnet_ip_recv_small(data,size);
-			break;
-			
-		case TNET_RPC:
-			tnet_rpc_recv(data,size);
-			break;
-			
-		default:
-			tnet_stats.errors++;
-			printk("unknown Tnet type %ld\n",type);
-		}
-
-#if DEBUG
-		printk("CID(%d) recvd %d bytes of type %d read_ptr=%x\n",
-		       _cid,size,type,system_read_ptr);
-#endif
-	}
-	restore_flags(flags);
-}
-
-
-#define COMPLETION_LIST_LENGTH 256
-
-static unsigned completion_list_rp = 0;
-static unsigned completion_list_wp = 0;
-
-static volatile struct completion_struct {
-  u_long flag;
-  void (*fn)(int a1,...);
-  u_long args[2];
-} completion_list[COMPLETION_LIST_LENGTH];
-
-
-void tnet_check_completion(void)
-{
-	struct completion_struct *cs;
-	unsigned flags;
-
-	tnet_recv();  
-
-	if (completion_list[completion_list_rp].flag != 2)
-		return;
-
-	save_flags(flags); cli();
-  
-	while (completion_list[completion_list_rp].flag == 2) {
-		cs = &completion_list[completion_list_rp];
-		cs->flag = 0;
-		if (++completion_list_rp == COMPLETION_LIST_LENGTH)
-			completion_list_rp = 0;
-
-		restore_flags(flags);
-
-		cs->fn(cs->args[0],cs->args[1]);
-
-		if (completion_list[completion_list_rp].flag != 2)
-			return;
-
-		save_flags(flags); cli();
-	}
-	
-	restore_flags(flags);
-}
-
-
-static u_long tnet_add_completion(void (*fn)(int a1,...),int a1,int a2)
-{
-        unsigned flags;
-        struct completion_struct *cs;
-	
-	save_flags(flags); cli();
-
-	while (completion_list[completion_list_wp].flag != 0)
-		tnet_check_completion();
-
-	cs = &completion_list[completion_list_wp];
-
-	if (++completion_list_wp == COMPLETION_LIST_LENGTH)
-		completion_list_wp = 0;
-
-	restore_flags(flags);
-
-        cs->flag = 1;
-        cs->fn = fn;
-	cs->args[0] = a1;
-	cs->args[1] = a2;
-
-        return (u_long)&cs->flag;
-}
-
-
-/* 
- * send a message to the tnet ringuffer on another cell. When the send has
- * completed call fn with the args supplied 
- */
-static void tnet_send(long cid,long type,char *src_addr,long byteSize,
-		      int immediate,u_long flag)
-{
-	int wordSize;
-	int byteAlign, byteFix;
-	u_long src;
-	u_long info1, info2;
-	volatile u_long *entry = (volatile u_long *)MSC_SEND_QUEUE_S;
-	SAVE_PID();
-
-	byteAlign = ((u_long)src_addr) & 0x3;
-	byteFix = byteSize & 0x3;
-	
-	src = (u_long)src_addr & ~3;
-	
-	wordSize = (byteSize + byteAlign + 3) >> 2;
-	
-	info1 = (_cid << 22) | (byteFix << 20) | wordSize;
-	info2 = (RBUF_SYSTEM<<28) | (byteAlign << 26) | type;
-	
-	*entry = tnet_rel_cid_table[cid];
-	*entry = wordSize;
-	*entry = (u_long)&system_recv_flag;
-	*entry = flag;
-	*entry = (u_long)src;
-	*entry = 0;
-	*entry = info1;
-	*entry = info2;
-	RESTORE_PID();
-	
-	ap_phys_put(cid,(u_long)&dummy,4,MC_INTP_0,0,0);
-	if (immediate && flag) 
-		ap_phys_put(_cid,(u_long)&dummy,4,MC_INTP_0,0,0);
-}
-
-
-static void free_skb(struct sk_buff *skb, int op)
-{
-	dev_kfree_skb(skb);
-}
-
-void tnet_send_ip(int cid,struct sk_buff *skb)
-{
-	char *data = skb->data + sizeof(struct cap_request);
-	int size = skb->len - sizeof(struct cap_request);
-	u_long flag;
-#if IP_DEBUG
-	int i;
-	for (i=0;i<size;i+=4)
-		printk("[%08x]%c",*(int *)(data+i),i==32?'\n':' ');
-	printk("\n");
-#endif
-	if (size > TNET_IP_THRESHOLD) {
-		int *info = (int *)skb->data; /* re-use the header */
-		info[0] = (int)data;
-		info[1] = size;
-		info[2] = tnet_add_completion(free_skb, (int)skb, 0);
-		tnet_send(cid,TNET_IP,info,sizeof(int)*3,0,0);
-	} else {
-		flag = tnet_add_completion(free_skb, (int)skb, 0);
-		tnet_send(cid,TNET_IP_SMALL,data,size,0,flag);
-		tnet_stats.small_packets_sent++;
-	}
-	tnet_stats.packets_sent++;
-	tnet_stats.bytes_sent += size;
-#if IP_DEBUG
-	printk("CID(%d) sent IP of size %d to %d\n",_cid,size,cid);
-#endif
-}
-
-static void reschedule(void)
-{
-	current->need_resched = 1;
-	mark_bh(TQUEUE_BH);
-}
-
-
-/* make a remote procedure call 
-   If free is set then free the data after sending it 
-   The first element of data is presumed to be a function pointer
-*/
-int tnet_rpc(int cell,char *data,int size,int free)
-{
-	unsigned flag=0;
-
-	if (free) {
-		flag = tnet_add_completion(kfree,data,0);
-	}
-
-	tnet_send(cell,TNET_RPC,data,size,0,flag);
-	return 0;
-}
-
-
-static void iport_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int i;
-	u_long intr = MC_IN(MC_INTR_PORT);
-
-	for (i=0;i<4;i++) {
-		if (intr & (AP_INTR_REQ << iports[i].shift)) {
-			MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift);
-			if (iports[i].fn) iports[i].fn();
-		}
-	}
-}
-
-
-void ap_tnet_init(void)
-{
-	int i;
-
-	bif_add_debug_key('T',tnet_info,"Tnet status");
-
-	memset(completion_list,0,sizeof(completion_list));
-	
-	request_irq(APIPORT_IRQ, iport_irq, SA_INTERRUPT, "iport", 0);
-
-	for (i=0;i<4;i++) {
-		MC_OUT(MC_INTR_PORT,AP_CLR_INTR_REQ << iports[i].shift);
-		MC_OUT(MC_INTR_PORT,AP_CLR_INTR_MASK << iports[i].shift);
-	}    
-
-
-	tnet_rel_cid_table = (int *)kmalloc(sizeof(int)*_ncel,GFP_ATOMIC);
-	for (i=0;i<_ncel;i++)
-		tnet_rel_cid_table[i] = rel_cid(i);
-
-	if(_cid == 0) {
-		xy_global_head  = (((_ncelx -1) << 8) & 0xff00) | 
-			((_ncely - 1) & 0xff);
-	}
-	else {
-		for(i = 1; i < _ncel; i *= 2){
-			if(i & _cid) {	
-				int	rcidx = (_cid-i)%_ncelx - _cid%_ncelx;
-				int	rcidy = (_cid-i)/_ncelx - _cid/_ncelx;
-				xy_global_head  = ((rcidx << 8) & 0xff00) | 
-					(rcidy & 0xff);
-				break;	
-			}
-		}
-	}
-}
-
-static void tnet_info(void)
-{
-	struct completion_struct *cs;
-	
-	printk(
-	       "errors=%d  alloc_errors=%d
-bytes_received=%d  bytes_sent=%d
-packets_received=%d  packets_sent=%d
-small_received=%d  small_sent=%d
-",
-	       tnet_stats.errors, tnet_stats.alloc_errors,
-	       tnet_stats.bytes_received,
-	       tnet_stats.bytes_sent, tnet_stats.packets_received,
-	       tnet_stats.packets_sent, tnet_stats.small_packets_received,
-	       tnet_stats.small_packets_sent);
-
-	printk("recv_flag=%d recv_count=%d read_ptr=%d\n",
-	       system_recv_flag,system_recv_count,system_read_ptr);
-	printk("completion_list_rp=%d  completion_list_wp=%d\n",
-	       completion_list_rp,completion_list_wp);
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/ap1000/util.c linux/arch/sparc/ap1000/util.c
--- v2.3.41/linux/arch/sparc/ap1000/util.c	Wed May 12 08:41:12 1999
+++ linux/arch/sparc/ap1000/util.c	Wed Dec 31 16:00:00 1969
@@ -1,436 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* general utility functions for the AP1000 */
-
-#include <linux/sched.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/asi.h>
-#include <asm/delay.h>
-#include <asm/pgtable.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/mpp.h>
-
-#define APLOG 0
-
-struct cap_init cap_init;
-
-/* find what cell id we are running on */
-int mpp_cid(void)
-{
-  return(BIF_IN(BIF_CIDR1));
-}
-
-/* find how many cells there are */
-int mpp_num_cells(void)
-{
-  return(cap_init.numcells);
-}
-
-/* this can be used to ensure some data is readable before DMAing
-   it. */
-int ap_verify_data(char *d,int len)
-{
-	int res = 0;
-	while (len--) res += *d++;
-	return res;
-}
-
-/* How many BogoMIPS in the entire machine
-Don't worry about float because when it gets this big, it's irrelevant */
-int mpp_agg_bogomips(void)
-{
-  return mpp_num_cells()*loops_per_sec/500000; /* cheat in working it out */
-}
-
-/* Puts multiprocessor configuration info into a buffer */
-int get_mppinfo(char *buffer)
-{
-  return sprintf(buffer,
-		 "Machine Type:\t\t: %s\nNumber of Cells\t\t: %d\nAggregate BogoMIPS\t: %d\n",
-		 "Fujitsu AP1000+",
-		 mpp_num_cells(),
-		 mpp_agg_bogomips());
-}
-
-#if APLOG
-static int do_logging = 0;
-
-
-void ap_log(char *buf,int len)
-{
-#define LOG_MAGIC 0x8736526
-	static char *logbase;
-	static char *logptr;
-	static int logsize = 1024;
-	int l,i;
-
-	if (buf == NULL && len == -1) {
-		logbase = kmalloc(logsize + 8,GFP_ATOMIC);
-		
-		if (!logbase) {
-			printk("log init failed\n");
-			return;
-		}
-		for (i=0;i<logsize;i++)
-			if (logbase[8+i] == '|')
-				logbase[8+i] = '_';
-
-		if ((*(int *)logbase) == LOG_MAGIC) {
-			int oldoffset = *(int *)(logbase + 4);
-			printk("==%3d== START OLD LOG ==\n",mpp_cid());
-			ap_write(1,logbase + 8 + oldoffset,logsize - oldoffset);
-			ap_write(1,logbase+8,oldoffset);
-			printk("==%3d== END OLD LOG ==\n",mpp_cid());
-		}
-		*(int *)logbase = LOG_MAGIC;
-		*(int *)(logbase+4) = 0;
-		logbase += 8;
-		logptr = logbase;
-		memset(logbase,0,logsize);
-		do_logging = 1;
-		return;
-	}
-
-	if (!do_logging) return;
-
-	while (len) {
-		l = logsize - (logptr - logbase);
-		if (l > len) l = len;
-		memcpy(logptr,buf,l);
-		len -= l;
-		logptr += l;
-		if (logptr == logbase + logsize) 
-			logptr = logbase;
-	}
-	*(int *)(logbase - 4) = (logptr - logbase);
-}
-#endif
-
-int ap_current_uid = -1;
-
-/* set output only to a particular uid */
-void ap_set_user(int uid)
-{
-	ap_current_uid = uid;
-}
-
-/* write some data to a filedescriptor on the front end */
-int ap_write(int fd,char *buf,int nbytes)
-{
-	struct cap_request req;
-
-	if (nbytes == 0) return 0;
-
-#if APLOG
-	ap_log(buf,nbytes);
-	
-	if (buf[0] == '|') return nbytes;
-#endif
-
-	req.cid = mpp_cid();
-	req.type = REQ_WRITE;
-	req.size = nbytes + sizeof(req);
-	req.data[0] = fd;
-	if (ap_current_uid == -1 && current && current->pid) {
-		req.data[1] = current->uid;
-	} else {
-		req.data[1] = ap_current_uid;
-	}
-	req.header = MAKE_HEADER(HOST_CID);
-	
-	bif_queue(&req,buf,nbytes);
-
-	return(nbytes);
-}
-
-/* write one character to stdout on the front end */
-int ap_putchar(char c)
-{
-  struct cap_request req;
-
-#if APLOG
-  ap_log(&c,1);
-#endif
-
-  req.cid = mpp_cid();
-  req.type = REQ_PUTCHAR;
-  req.size = sizeof(req);
-  req.data[0] = c;
-  req.header = MAKE_HEADER(HOST_CID);
-
-  bif_queue(&req,0,0);
-
-  return(0);
-}
-
-/* start the debugger (kgdb) on this cell */
-void ap_start_debugger(void)
-{
-	static int done = 0;
-	extern void set_debug_traps(void);
-	extern void breakpoint(void);
-	if (!done)
-		set_debug_traps();
-	done = 1;
-	breakpoint();
-}
-
-void ap_panic(char *msg,int a1,int a2,int a3,int a4,int a5)
-{
-	ap_led(0xAA);
-	printk(msg,a1,a2,a3,a4,a5);
-	ap_start_debugger();
-}
-
-void ap_printk(char *msg,int a1,int a2,int a3,int a4,int a5)
-{
-  printk(msg,a1,a2,a3,a4,a5);
-  /* bif_queue_flush(); */
-}
-
-/* get the command line arguments from the front end */
-void ap_getbootargs(char *buf)
-{
-    struct cap_request req;
-    int size;
-
-    req.cid = mpp_cid();
-    req.type = REQ_GETBOOTARGS;
-    req.size = sizeof(req);
-    req.header = MAKE_HEADER(HOST_CID);
-    
-    write_bif_polled((char *)&req,sizeof(req),NULL,0);
-
-    ap_wait_request(&req,REQ_GETBOOTARGS); 
-
-    size = req.size - sizeof(req);
-    if (size == 0)
-      buf[0] = '\0';
-    else {
-      read_bif(buf, size);
-    }
-
-    req.cid = mpp_cid();
-    req.type = REQ_INIT;
-    req.size = sizeof(req);
-    req.header = MAKE_HEADER(HOST_CID);
-
-    write_bif_polled((char *)&req,sizeof(req),NULL,0);
-
-    ap_wait_request(&req,REQ_INIT);
-
-    if (req.size != sizeof(req))
-      read_bif((char *)&cap_init,req.size - sizeof(req));
-    if ((req.size - sizeof(req)) != sizeof(cap_init))
-      printk("WARNING: Init structure is wrong size, recompile util.c\n");
-
-    if (cap_init.gdbcell == mpp_cid())
-      ap_start_debugger();
-
-    printk("Got command line arguments from server\n");
-}
-
-/* a useful utility for debugging pagetable setups */
-void show_mapping_ctx(unsigned *ctp,int context,unsigned Vm)
-{  
-  unsigned *pgtable;
-  int entry[3];
-  int level = 0;
-
-  if (!ctp) ctp = (unsigned *)mmu_p2v(srmmu_get_ctable_ptr());
-
-  printk("ctp=0x%x ",(int)ctp);
-
-  pgtable = ctp + context;
-
-  /* get the virtual page */
-  Vm = Vm>>12;
-
-  printk("Vm page 0x%x is ",Vm);  
-
-  entry[0] = Vm>>12;
-  entry[1] = (Vm>>6) & 0x3f;
-  entry[2] = Vm & 0x3f;
-
-  while (1) {
-
-#if 1
-    printk("(%08x) ",pgtable[0]);
-#endif
-
-  if ((pgtable[0] & 3) == 2) {
-    printk("mapped at level %d to 0x%x\n",level,pgtable[0]>>8);
-    return;
-  }
-
-  if ((pgtable[0] & 3) == 0) {
-    printk("unmapped at level %d\n",level);
-    return;
-  }
-
-  if ((pgtable[0] & 3) == 3) {
-    printk("invalid at level %d\n",level);
-    return;
-  }
-
-  if ((pgtable[0] & 3) == 1) {
-    pgtable = (unsigned *)(((pgtable[0]>>2)<<6)|0xf0000000);
-    pgtable += entry[level];
-    level++;
-  }
-  } 
-}
-
-
-
-static unsigned char current_led = 0;
-
-void ap_led(unsigned char d)
-{
-  unsigned paddr = 0x1000;
-  unsigned word = 0xff & ~d;
-  current_led = d;
-  __asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-		       "r" (word), "r" (paddr), "i" (0x2c) :
-		       "memory");
-}
-
-void ap_xor_led(unsigned char d)
-{
-	ap_led(current_led ^ d);
-}
-
-void ap_set_led(unsigned char d)
-{
-	ap_led(current_led | d);
-}
-
-void ap_unset_led(unsigned char d)
-{
-	ap_led(current_led & ~d);
-}
-
-
-void kbd_put_char(char c)
-{
-  ap_putchar(c);
-}
-
-
-void ap_enter_irq(int irq)
-{
-  unsigned char v = current_led;
-  switch (irq) {
-  case 2: v |= (1<<1); break;
-  case 4: v |= (1<<2); break;
-  case 8: v |= (1<<3); break;
-  case 9: v |= (1<<4); break;
-  case 10: v |= (1<<5); break;
-  case 11: v |= (1<<6); break;
-  default: v |= (1<<7); break;
-  }
-  ap_led(v);
-}
-
-void ap_exit_irq(int irq)
-{
-  unsigned char v = current_led;
-  switch (irq) {
-  case 2: v &= ~(1<<1); break;
-  case 4: v &= ~(1<<2); break;
-  case 8: v &= ~(1<<3); break;
-  case 9: v &= ~(1<<4); break;
-  case 10: v &= ~(1<<5); break;
-  case 11: v &= ~(1<<6); break;
-  default: v &= ~(1<<7); break;
-  }
-  ap_led(v);
-}
-
-
-static DECLARE_WAIT_QUEUE_HEAD(timer_wait);
-
-static void wait_callback(unsigned long _ignored)
-{
-  wake_up(&timer_wait);
-}
-
-/* wait till x == *p */
-int wait_on_int(volatile int *p,int x,int interval)
-{
-	struct timer_list *timer = kmalloc(sizeof(*timer),GFP_KERNEL);
-	if (!timer) panic("out of memory in wait_on_int()\n");
-	timer->next = NULL;
-	timer->prev = NULL;
-	timer->data = 0;
-	timer->function = wait_callback;
-	while (*p != x) {
-		timer->expires = jiffies + interval;
-		add_timer(timer);
-		interruptible_sleep_on(&timer_wait);
-		del_timer(timer);
-		if (signal_pending(current))
-			return -EINTR;
-	}
-	kfree_s(timer,sizeof(*timer));
-	return 0;
-}
-
-
-/* an ugly hack to get nfs booting from a central cell to work */
-void ap_nfs_hook(unsigned long server)
-{
-  unsigned cid = server - cap_init.baseIP;
-  if (cid < cap_init.bootcid + cap_init.numcells &&
-      cid != mpp_cid()) {
-    unsigned end = jiffies + 20*HZ;
-    /* we are booting from another cell */
-    printk("waiting for the master cell\n");
-    while (time_before(jiffies, end)) ;
-    printk("continuing\n");
-  }
-}
-
-/* convert a IP address to a cell id */
-int ap_ip_to_cid(u_long ip)
-{
-  unsigned cid;
-
-  if ((ip & cap_init.netmask) != (cap_init.baseIP & cap_init.netmask))
-    return -1;
-
-  if ((ip & ~cap_init.netmask) == AP_ALIAS_IP)
-    cid = cap_init.bootcid;
-  else
-    cid = ip - cap_init.baseIP;
-  if (cid >= cap_init.bootcid + cap_init.numcells)
-    return -1;
-  return cid;
-}
-
-
-void ap_reboot(char *bootstr)
-{
-	printk("cell(%d) - don't know how to reboot\n",mpp_cid());
-	sti();
-	while (1) ;
-}
-
-
-void dumb_memset(char *buf,char val,int len)
-{
-	while (len--) *buf++ = val;
-}
-
-void ap_init_time(struct timeval *xtime)
-{
-	xtime->tv_sec = cap_init.init_time;
-	xtime->tv_usec = 0;
-}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.3.41/linux/arch/sparc/config.in	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/config.in	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.81 2000/01/22 05:14:44 zaitcev Exp $
+# $Id: config.in,v 1.84 2000/01/31 21:10:04 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -19,43 +19,33 @@
 
 bool 'Symmetric multi-processing support (does not work on sun4/sun4c)' CONFIG_SMP
 
-bool 'Support for AP1000 multicomputer' CONFIG_AP1000
-if [ "$CONFIG_AP1000" = "y" ]; then
-   define_bool CONFIG_NO_KEYBOARD y
-   define_bool CONFIG_FDDI y
-   define_bool CONFIG_APFDDI y
-   define_bool CONFIG_APBLOCK y
-   define_bool CONFIG_APBIF y
-   tristate '  OPIU DDV Driver' CONFIG_DDV
-else
-   bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
-   if [ "$CONFIG_SUN4" != "y" ]; then
-      bool '  Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI
-      source drivers/pci/Config.in
-   fi
-
-   mainmenu_option next_comment
-   comment 'Console drivers'
-   bool 'PROM console' CONFIG_PROM_CONSOLE
-   source drivers/video/Config.in
-   endmenu
+bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
+if [ "$CONFIG_SUN4" != "y" ]; then
+   bool '  Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI
+   source drivers/pci/Config.in
+fi
 
-   # Global things across all Sun machines.
-   define_bool CONFIG_SBUS y
-   define_bool CONFIG_SBUSCHAR y
-   define_bool CONFIG_BUSMOUSE y
-   define_bool CONFIG_SUN_MOUSE y
-   define_bool CONFIG_SERIAL y
-   define_bool CONFIG_SUN_SERIAL y
-   define_bool CONFIG_SERIAL_CONSOLE y
-   define_bool CONFIG_SUN_KEYBOARD y
-   define_bool CONFIG_SUN_CONSOLE y
-   define_bool CONFIG_SUN_AUXIO y
-   define_bool CONFIG_SUN_IO y
-   if [ "$CONFIG_SUN4" != "y" ]; then
-      source drivers/sbus/char/Config.in
-      source drivers/sbus/audio/Config.in
-   fi
+mainmenu_option next_comment
+comment 'Console drivers'
+bool 'PROM console' CONFIG_PROM_CONSOLE
+source drivers/video/Config.in
+endmenu
+
+# Global things across all Sun machines.
+define_bool CONFIG_SBUS y
+define_bool CONFIG_SBUSCHAR y
+define_bool CONFIG_BUSMOUSE y
+define_bool CONFIG_SUN_MOUSE y
+define_bool CONFIG_SERIAL y
+define_bool CONFIG_SUN_SERIAL y
+define_bool CONFIG_SERIAL_CONSOLE y
+define_bool CONFIG_SUN_KEYBOARD y
+define_bool CONFIG_SUN_CONSOLE y
+define_bool CONFIG_SUN_AUXIO y
+define_bool CONFIG_SUN_IO y
+if [ "$CONFIG_SUN4" != "y" ]; then
+   source drivers/sbus/char/Config.in
+   source drivers/sbus/audio/Config.in
 fi
 
 tristate 'Openprom tree appears in /proc/openprom' CONFIG_SUN_OPENPROMFS
@@ -161,7 +151,10 @@
       tristate '  Dummy net driver support' CONFIG_DUMMY
       tristate '  PPP (point-to-point) support' CONFIG_PPP
       if [ ! "$CONFIG_PPP" = "n" ]; then
-	 comment 'CCP compressors for PPP are only built as modules.'
+        dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
+        dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
+        dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+        dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
       fi
       tristate '  SLIP (serial line) support' CONFIG_SLIP
       if [ "$CONFIG_SLIP" != "n" ]; then
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.3.41/linux/arch/sparc/defconfig	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc/defconfig	Mon Jan 31 23:37:19 2000
@@ -14,7 +14,6 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 # CONFIG_SMP is not set
-# CONFIG_AP1000 is not set
 # CONFIG_SUN4 is not set
 # CONFIG_PCI is not set
 
@@ -22,7 +21,6 @@
 # Console drivers
 #
 CONFIG_PROM_CONSOLE=y
-CONFIG_FB=y
 
 #
 # Frame-buffer support
@@ -217,10 +215,10 @@
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 CONFIG_PPP=m
-
-#
-# CCP compressors for PPP are only built as modules.
-#
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -242,10 +240,12 @@
 #
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
 # CONFIG_ADFS_FS is not set
 CONFIG_AFFS_FS=m
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
+# CONFIG_BFS_FS_WRITE is not set
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
 # CONFIG_UMSDOS_FS is not set
@@ -256,23 +256,27 @@
 # CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=m
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_SYSV_FS=m
 # CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
 CONFIG_UFS_FS=m
-CONFIG_UFS_FS_WRITE=y
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 CONFIG_CODA_FS=m
 CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=m
 # CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
@@ -295,7 +299,6 @@
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SGI_PARTITION is not set
 CONFIG_SUN_PARTITION=y
 CONFIG_NLS=y
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v2.3.41/linux/arch/sparc/kernel/head.S	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/kernel/head.S	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.101 1999/12/02 08:34:56 jj Exp $
+/* $Id: head.S,v 1.102 2000/01/29 01:08:54 anton Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -483,10 +483,8 @@
 1:
 		mov	%o7, %g3
 
-#ifndef CONFIG_AP1000
 		tst	%o0
 		be	no_sun4u_here
-#endif
 		 mov	%g4, %o7		/* Previous %o7. */
 	
 		mov	%o0, %l0		! stash away romvec
@@ -762,11 +760,6 @@
  * I figure out and store nwindows and nwindowsm1 later on.
  */
 execute_in_high_mem:
-#if CONFIG_AP1000
-                /* we don't have a prom :-( */
-                b sun4m_init
-                nop
-#endif
 		mov	%l0, %o0		! put back romvec
 		mov	%l1, %o1		! and debug_vec
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c
--- v2.3.41/linux/arch/sparc/kernel/ioport.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/ioport.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.29 2000/01/22 07:35:25 zaitcev Exp $
+/* $Id: ioport.c,v 1.30 2000/01/28 13:41:55 jj Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.3.41/linux/arch/sparc/kernel/irq.c	Tue Jan  4 13:57:16 2000
+++ linux/arch/sparc/kernel/irq.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.99 1999/12/27 06:08:29 anton Exp $
+/*  $Id: irq.c,v 1.100 2000/01/29 01:38:04 anton 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
@@ -738,12 +738,6 @@
 	case sun4d:
 		sun4d_init_IRQ();
 		break;
-
-	case ap1000:
-#if CONFIG_AP1000
-		ap_init_IRQ();;
-		break;
-#endif
 
 	default:
 		prom_printf("Cannot initialize IRQ's on this Sun machine...");
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.3.41/linux/arch/sparc/kernel/process.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/process.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.144 2000/01/21 11:38:39 jj Exp $
+/*  $Id: process.c,v 1.145 2000/01/29 01:08:56 anton Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -266,9 +266,6 @@
 
 void show_regs(struct pt_regs * regs)
 {
-#if __MPP__
-	printk("CID: %d\n",mpp_cid());
-#endif
         printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs->psr,
 	       regs->pc, regs->npc, regs->y);
 	printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx ",
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.3.41/linux/arch/sparc/kernel/setup.c	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/kernel/setup.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.113 1999/12/16 14:37:35 anton Exp $
+/*  $Id: setup.c,v 1.114 2000/01/29 01:08:57 anton Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -201,11 +201,6 @@
 				prom_printf("KGDB: Using serial line /dev/ttyb.\n");
 				break;
 #endif
-#ifdef CONFIG_AP1000
-			case 'c':
-				printk("KGDB: AP1000+ debugging\n");
-				break;
-#endif
 			default:
 				printk("KGDB: Unknown tty line.\n");
 				break;
@@ -326,10 +321,6 @@
 		prom_halt();
 	}
 #endif
-#if CONFIG_AP1000
-	sparc_cpu_model=ap1000;
-	strcpy(&cputypval, "ap+");
-#endif
 	printk("ARCH: ");
 	switch(sparc_cpu_model) {
 	case sun4:
@@ -349,10 +340,6 @@
 		break;
 	case sun4u:
 		printk("SUN4U\n");
-		break;
-	case ap1000:
-		register_console(&prom_console);
-		printk("AP1000\n");
 		break;
 	default:
 		printk("UNKNOWN!\n");
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.3.41/linux/arch/sparc/kernel/sparc_ksyms.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.87 2000/01/21 17:41:14 anton Exp $
+/* $Id: sparc_ksyms.c,v 1.88 2000/01/28 13:41:55 jj Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.3.41/linux/arch/sparc/kernel/sys_sparc.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/sys_sparc.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.57 2000/01/21 11:38:42 jj Exp $
+/* $Id: sys_sparc.c,v 1.59 2000/01/29 07:40:10 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -383,12 +383,3 @@
 	up_read(&uts_sem);
 	return err;
 }
-
-
-#ifndef CONFIG_AP1000
-/* only AP+ systems have sys_aplib */
-asmlinkage int sys_aplib(void)
-{
-	return -ENOSYS;
-}
-#endif
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.41/linux/arch/sparc/kernel/sys_sunos.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.111 2000/01/22 05:17:55 anton Exp $
+/* $Id: sys_sunos.c,v 1.112 2000/01/29 07:40:11 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.3.41/linux/arch/sparc/kernel/systbls.S	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/systbls.S	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.91 2000/01/16 06:20:44 davem Exp $
+/* $Id: systbls.S,v 1.93 2000/01/29 16:41:18 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -47,7 +47,7 @@
 /*130*/	.long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
 /*135*/	.long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
 /*140*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
-/*145*/	.long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
+/*145*/	.long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
 /*155*/	.long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
@@ -70,7 +70,7 @@
 /*240*/	.long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 /*245*/	.long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-/*255*/	.long sys_aplib, sys_nis_syscall
+/*255*/	.long sys_nis_syscall, sys_nis_syscall
 
 #ifdef CONFIG_SUNOS_EMUL
 	/* Now the SunOS syscall table. */
@@ -164,6 +164,6 @@
 	.long sunos_nosys, sunos_nosys, sunos_nosys
 	.long sunos_nosys, sunos_nosys
 /*250*/	.long sunos_nosys, sunos_nosys, sunos_nosys
-	.long sunos_nosys, sunos_nosys, sys_aplib
+	.long sunos_nosys, sunos_nosys, sunos_nosys
 
 #endif
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v2.3.41/linux/arch/sparc/kernel/time.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/kernel/time.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.50 2000/01/21 04:35:53 anton Exp $
+/* $Id: time.c,v 1.51 2000/01/29 01:08:59 anton Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -353,12 +353,6 @@
 	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
 	btfixup();
 
-#if CONFIG_AP1000
-	init_timers(timer_interrupt);
-	ap_init_time(&xtime);
-        return;
-#endif
-
 	if (ARCH_SUN4)
 		sun4_clock_probe();
 	else
@@ -451,14 +445,6 @@
  */
 void do_gettimeofday(struct timeval *tv)
 {
-#if CONFIG_AP1000
-	unsigned long flags;
-
-	save_and_cli(flags);
-	ap_gettimeofday(&xtime);
-	*tv = xtime;
-	restore_flags(flags);
-#else /* !(CONFIG_AP1000) */
 	/* Load doubles must be used on xtime so that what we get
 	 * is guarenteed to be atomic, this is why we can run this
 	 * with interrupts on full blast.  Don't touch this... -DaveM
@@ -493,7 +479,6 @@
 	sub	%o5, %o2, %o5
 	st	%o4, [%o0 + 0x0]
 1:	st	%o5, [%o0 + 0x4]");
-#endif
 }
 
 void do_settimeofday(struct timeval *tv)
@@ -505,13 +490,11 @@
 
 static void sbus_do_settimeofday(struct timeval *tv)
 {
-#if !CONFIG_AP1000
 	tv->tv_usec -= do_gettimeoffset();
 	if(tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
 		tv->tv_sec--;
 	}
-#endif
 	xtime = *tv;
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v2.3.41/linux/arch/sparc/mm/Makefile	Wed Dec 29 13:13:13 1999
+++ linux/arch/sparc/mm/Makefile	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.35 1999/10/09 05:32:01 zaitcev Exp $
+# $Id: Makefile,v 1.36 2000/01/29 01:09:05 anton Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -9,9 +9,6 @@
 
 O_TARGET := mm.o
 O_OBJS   := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
-ifeq ($(CONFIG_AP1000),y)
-O_OBJS	 += asyncd.o
-endif
 ifeq ($(CONFIG_SUN4),y)
 O_OBJS	 += nosrmmu.o
 else
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/mm/asyncd.c linux/arch/sparc/mm/asyncd.c
--- v2.3.41/linux/arch/sparc/mm/asyncd.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/mm/asyncd.c	Wed Dec 31 16:00:00 1969
@@ -1,290 +0,0 @@
-/*  $Id: asyncd.c,v 1.20 2000/01/21 11:38:47 jj Exp $
- *  The asyncd kernel daemon. This handles paging on behalf of 
- *  processes that receive page faults due to remote (async) memory
- *  accesses. 
- *
- *  Idea and skeleton code courtesy of David Miller (bless his cotton socks)
- *
- *  Implemented by tridge
- */
-
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/swap.h>
-#include <linux/fs.h>
-#include <linux/config.h>
-#include <linux/interrupt.h>
-
-#include <asm/dma.h>
-#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for memcpy_to/fromfs */
-#include <asm/bitops.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-
-#define DEBUG 0
-
-#define WRITE_LIMIT 100
-#define LOOP_LIMIT 200
-
-static struct {
-	int faults, read, write, success, failure, errors;
-} stats;
-
-/* 
- * The wait queue for waking up the async daemon:
- */
-static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait);
-
-struct async_job {
-	volatile struct async_job *next;
-	int taskid;
-	struct mm_struct *mm;
-	unsigned long address;
-	int write;
-	void (*callback)(int,unsigned long,int,int);
-};
-
-static volatile struct async_job *async_queue = NULL;
-static volatile struct async_job *async_queue_end = NULL;
-
-static void add_to_async_queue(int taskid,
-			       struct mm_struct *mm,
-			       unsigned long address,
-			       int write,
-			       void (*callback)(int,unsigned long,int,int))
-{
-	struct async_job *a = kmalloc(sizeof(*a),GFP_ATOMIC);
-
-	if (!a) {
-		printk("ERROR: out of memory in asyncd\n");
-		a->callback(taskid,address,write,1);
-		return;
-	}
-
-	if (write)
-		stats.write++;
-	else
-		stats.read++;
-
-	a->next = NULL;
-	a->taskid = taskid;
-	a->mm = mm;
-	a->address = address;
-	a->write = write;
-	a->callback = callback;
-
-	if (!async_queue) {
-		async_queue = a;
-	} else {
-		async_queue_end->next = a;
-	}
-	async_queue_end = a;
-}
-
-
-void async_fault(unsigned long address, int write, int taskid,
-		 void (*callback)(int,unsigned long,int,int))
-{
-	struct task_struct *tsk = task[taskid];
-	struct mm_struct *mm = tsk->mm;
-
-	stats.faults++;
-
-#if 0
-	printk("paging in %x for task=%d\n",address,taskid);
-#endif
-
-	add_to_async_queue(taskid, mm, address, write, callback);
-	wake_up(&asyncd_wait);  
-	mark_bh(TQUEUE_BH);
-}
-
-static int fault_in_page(int taskid,
-			 struct vm_area_struct *vma,
-			 unsigned address,int write)
-{
-	static unsigned last_address;
-	static int last_task, loop_counter;
-	struct task_struct *tsk = task[taskid];
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	siginfo_t info;
-
-	if (!tsk || !tsk->mm)
-		return 1;
-
-	if (!vma || (write && !(vma->vm_flags & VM_WRITE)))
-	  goto bad_area;
-	if (vma->vm_start > address)
-	  goto bad_area;
-
-	if (address == last_address && taskid == last_task) {
-		loop_counter++;
-	} else {
-		loop_counter = 0;
-		last_address = address; 
-		last_task = taskid;
-	}
-
-	if (loop_counter == WRITE_LIMIT && !write) {
-		printk("MSC bug? setting write request\n");
-		stats.errors++;
-		write = 1;
-	}
-
-	if (loop_counter == LOOP_LIMIT) {
-		printk("MSC bug? failing request\n");
-		stats.errors++;
-		return 1;
-	}
-
-	pgd = pgd_offset(vma->vm_mm, address);
-	pmd = pmd_alloc(pgd,address);
-	if(!pmd)
-		goto no_memory;
-	pte = pte_alloc(pmd, address);
-	if(!pte)
-		goto no_memory;
-	if(!pte_present(*pte)) {
-		handle_mm_fault(tsk, vma, address, write);
-		goto finish_up;
-	}
-	set_pte(pte, pte_mkyoung(*pte));
-	flush_tlb_page(vma, address);
-	if(!write)
-		goto finish_up;
-	if(pte_write(*pte)) {
-		set_pte(pte, pte_mkdirty(*pte));
-		flush_tlb_page(vma, address);
-		goto finish_up;
-	}
-	handle_mm_fault(tsk, vma, address, write);
-
-	/* Fall through for do_wp_page */
-finish_up:
-	stats.success++;
-	return 0;
-
-no_memory:
-	stats.failure++;
-	oom(tsk);
-	return 1;
-	
-bad_area:	  
-	stats.failure++;
-	info.si_signo = SIGSEGV;
-	info.si_errno = 0;
-	info.si_code = SEGV_MAPERR;
-	info.si_addr = (void *)address;
-	info.si_trapno = 0;
-	send_sig_info(SIGSEGV, &info, tsk);
-	return 1;
-}
-
-
-/* Note the semaphore operations must be done here, and _not_
- * in async_fault().
- */
-static void run_async_queue(void)
-{
-	int ret;
-	unsigned flags;
-
-	while (async_queue) {
-		volatile struct async_job *a;
-		struct mm_struct *mm;
-		struct vm_area_struct *vma;
-
-		save_flags(flags); cli();
-		a = async_queue;
-		async_queue = async_queue->next;
-		restore_flags(flags);
-
-		mm = a->mm;
-
-		down(&mm->mmap_sem);
-		vma = find_vma(mm, a->address);
-		ret = fault_in_page(a->taskid,vma,a->address,a->write);
-#if DEBUG
-		printk("fault_in_page(task=%d addr=%x write=%d) = %d\n",
-		       a->taskid,a->address,a->write,ret);
-#endif
-		a->callback(a->taskid,a->address,a->write,ret);
-		up(&mm->mmap_sem);
-		kfree_s((void *)a,sizeof(*a));
-	}
-}
-
-
-#if CONFIG_AP1000
-static void asyncd_info(void)
-{
-	printk("CID(%d) faults: total=%d  read=%d  write=%d  success=%d fail=%d err=%d\n",
-	       mpp_cid(),stats.faults, stats.read, stats.write, stats.success,
-	       stats.failure, stats.errors);
-}
-#endif
-
-
-/*
- * The background async daemon.
- * Started as a kernel thread from the init process.
- */
-int asyncd(void *unused)
-{
-	current->session = 1;
-	current->pgrp = 1;
-	sprintf(current->comm, "asyncd");
-	sigfillset(&current->blocked); /* block all signals */
-	recalc_sigpending(current);
-  
-	/* Give asyncd a realtime priority. */
-	current->policy = SCHED_FIFO;
-	current->priority = 32;  /* Fixme --- we need to standardise our
-				    namings for POSIX.4 realtime scheduling
-				    priorities.  */
-  
-	printk("Started asyncd\n");
-
-#if CONFIG_AP1000
-	bif_add_debug_key('a',asyncd_info,"stats on asyncd");
-#endif
-
-	while (1) {
-		unsigned flags;
-
-		save_flags(flags); cli();
-
-		while (!async_queue) {
-			spin_lock(&current->sigmask_lock);
-			flush_signals(current);
-			spin_unlock(&current->sigmask_lock);
-			interruptible_sleep_on(&asyncd_wait);
-			__sti(); cli();
-		}
-
-		restore_flags(flags);
-
-		run_async_queue();
-	}
-}
-
-#if CONFIG_AP1000
-
-static int __init init_ap1000(void)
-{
-	kernel_thread(asyncd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-	return 0;
-}
-
-module_init(init_ap1000)
-
-#endif
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.3.41/linux/arch/sparc/mm/init.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc/mm/init.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.78 2000/01/24 03:22:38 anton Exp $
+/*  $Id: init.c,v 1.79 2000/01/29 01:09:06 anton Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -238,15 +238,6 @@
 		sparc_unmapped_base = 0x50000000;
 		BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
 		break;
-
-	case ap1000:
-#if CONFIG_AP1000
-		apmmu_paging_init();
-		sparc_unmapped_base = 0x50000000;
-		BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
-		break;
-#endif
-
 	default:
 		prom_printf("paging_init: Cannot init paging on this Sparc\n");
 		prom_printf("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c
--- v2.3.41/linux/arch/sparc/mm/loadmmu.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc/mm/loadmmu.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.53 2000/01/09 10:46:50 anton Exp $
+/* $Id: loadmmu.c,v 1.54 2000/01/29 01:09:07 anton Exp $
  * loadmmu.c:  This code loads up all the mm function pointers once the
  *             machine type has been determined.  It also sets the static
  *             mmu values such as PAGE_NONE, etc.
@@ -39,11 +39,6 @@
 	case sun4d:
 		ld_mmu_srmmu();
 		break;
-	case ap1000:
-#if CONFIG_AP1000
-		ld_mmu_apmmu();
-		break;
-#endif
 	default:
 		prom_printf("load_mmu: %d unsupported\n", (int)sparc_cpu_model);
 		prom_halt();
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/prom/bootstr.c linux/arch/sparc/prom/bootstr.c
--- v2.3.41/linux/arch/sparc/prom/bootstr.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/prom/bootstr.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: bootstr.c,v 1.18 1999/08/31 06:54:45 davem Exp $
+/* $Id: bootstr.c,v 1.19 2000/01/29 01:09:11 anton Exp $
  * bootstr.c:  Boot string/argument acquisition from the PROM.
  *
  * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -55,11 +55,6 @@
 		 */
 		strncpy(barg_buf, *romvec->pv_v2bootargs.bootargs, BARG_LEN-1);
 		break;
-        case PROM_AP1000:
-#if CONFIG_AP1000
-                ap_getbootargs(barg_buf, BARG_LEN);
-                break;
-#endif
 	default:
 		break;
 	}
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c
--- v2.3.41/linux/arch/sparc/prom/console.c	Sun Oct  4 10:22:43 1998
+++ linux/arch/sparc/prom/console.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.20 1998/09/21 05:05:50 jj Exp $
+/* $Id: console.c,v 1.21 2000/01/29 01:09:12 anton Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
@@ -45,7 +45,6 @@
 			i = -1;
 		}
 		break;
-	case PROM_AP1000:
 	default:
 		i = -1;
 		break;
@@ -79,15 +78,6 @@
 		else
 			i = -1;
 		break;
-	case PROM_AP1000:
-#if CONFIG_AP1000
-		{
-		  extern void ap_putchar(char );
-		  ap_putchar(c);
-		  i = 0;
-		}
-#endif
-		break;
 	default:
 		i = -1;
 		break;
@@ -160,8 +150,6 @@
 				return PROMDEV_ITTYB;
 		}
 		return PROMDEV_I_UNK;
-	case PROM_AP1000:
-		return PROMDEV_I_UNK;
 	}
 }
 
@@ -219,7 +207,6 @@
 			};
 		}
 		break;
-	case PROM_AP1000:
 	default:
 	}
 	return PROMDEV_O_UNK;
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/prom/devops.c linux/arch/sparc/prom/devops.c
--- v2.3.41/linux/arch/sparc/prom/devops.c	Tue Apr 14 17:44:20 1998
+++ linux/arch/sparc/prom/devops.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: devops.c,v 1.11 1998/03/09 14:04:24 jj Exp $
+/* $Id: devops.c,v 1.12 2000/01/29 01:09:12 anton Exp $
  * devops.c:  Device operations using the PROM.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -31,7 +31,6 @@
 	case PROM_V3:
 		handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr);
 		break;
-        case PROM_AP1000:
 	default:
 		handle = -1;
 		break;
@@ -56,7 +55,6 @@
 	case PROM_V3:
 		(*(romvec->pv_v2devops.v2_dev_close))(dhandle);
 		break;
-        case PROM_AP1000:
 	default:
 		break;
 	};
@@ -81,7 +79,6 @@
 	case PROM_V3:
 		(*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
 		break;
-        case PROM_AP1000:
 	default:
 		break;
 	};
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/prom/init.c linux/arch/sparc/prom/init.c
--- v2.3.41/linux/arch/sparc/prom/init.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/prom/init.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.13 1999/08/31 06:54:45 davem Exp $
+/* $Id: init.c,v 1.14 2000/01/29 01:09:12 anton Exp $
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
@@ -41,10 +41,6 @@
 	extern struct linux_romvec *sun4_prom_init(void);
 	rp = sun4_prom_init();
 #endif
-#if CONFIG_AP1000
-	extern struct linux_romvec *ap_prom_init(void);
-	rp = ap_prom_init();
-#endif
 	romvec = rp;
 
 	switch(romvec->pv_romvers) {
@@ -60,10 +56,6 @@
 	case 40:
 		prom_vers = PROM_SUN4;
 		break;
-	case 42: /* why not :-) */
-		prom_vers = PROM_AP1000;
-		break;
-
 	default:
 		prom_printf("PROMLIB: Bad PROM version %d\n",
 			    romvec->pv_romvers);
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c
--- v2.3.41/linux/arch/sparc/prom/memory.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/prom/memory.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: memory.c,v 1.14 1999/08/31 06:54:46 davem Exp $
+/* $Id: memory.c,v 1.15 2000/01/29 01:09:12 anton Exp $
  * memory.c: Prom routine for acquiring various bits of information
  *           about RAM on the machine, both virtual and physical.
  *
@@ -194,19 +194,6 @@
 #endif
 		break;
 
-        case PROM_AP1000:
-#if CONFIG_AP1000
-		/* really simple memory map */
-		prom_phys_total[0].start_adr = 0x00000000;
-		prom_phys_total[0].num_bytes = ap_memory_size();
-		prom_phys_total[0].theres_more = 0x0;
-		prom_prom_taken[0].start_adr = 0x00000000; 
-		prom_prom_taken[0].num_bytes = 0x00000000;
-		prom_prom_taken[0].theres_more = 0x0;
-		prom_phys_avail[0].start_adr = 0x00000000;
-		prom_phys_avail[0].num_bytes = prom_phys_total[0].num_bytes;
-		prom_phys_avail[0].theres_more = 0x0;
-#endif
 	default:
 		break;
 	};
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/prom/mp.c linux/arch/sparc/prom/mp.c
--- v2.3.41/linux/arch/sparc/prom/mp.c	Tue Apr 14 17:44:20 1998
+++ linux/arch/sparc/prom/mp.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: mp.c,v 1.10 1998/03/09 14:04:26 jj Exp $
+/* $Id: mp.c,v 1.11 2000/01/29 01:09:12 anton Exp $
  * mp.c:  OpenBoot Prom Multiprocessor support routines.  Don't call
  *        these on a UP or else you will halt and catch fire. ;)
  *
@@ -29,7 +29,6 @@
 	switch(prom_vers) {
 	case PROM_V0:
 	case PROM_V2:
-	case PROM_AP1000:
 	default:
 		ret = -1;
 		break;
@@ -56,7 +55,6 @@
 	switch(prom_vers) {
 	case PROM_V0:
 	case PROM_V2:
-	case PROM_AP1000:
 	default:
 		ret = -1;
 		break;
@@ -83,7 +81,6 @@
 	switch(prom_vers) {
 	case PROM_V0:
 	case PROM_V2:
-	case PROM_AP1000:
 	default:
 		ret = -1;
 		break;
@@ -110,7 +107,6 @@
 	switch(prom_vers) {
 	case PROM_V0:
 	case PROM_V2:
-	case PROM_AP1000:
 	default:
 		ret = -1;
 		break;
diff -u --recursive --new-file v2.3.41/linux/arch/sparc/prom/printf.c linux/arch/sparc/prom/printf.c
--- v2.3.41/linux/arch/sparc/prom/printf.c	Sat Nov  9 00:12:28 1996
+++ linux/arch/sparc/prom/printf.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: printf.c,v 1.5 1996/04/04 16:31:07 tridge Exp $
+/* $Id: printf.c,v 1.6 2000/01/29 01:09:12 anton Exp $
  * printf.c:  Internal prom library printf facility.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -28,16 +28,12 @@
 
 	bptr = ppbuf;
 
-#if CONFIG_AP1000
-        ap_write(1,bptr,strlen(bptr));
-#else
 	while((ch = *(bptr++)) != 0) {
 		if(ch == '\n')
 			prom_putchar('\r');
 
 		prom_putchar(ch);
 	}
-#endif
 	va_end(args);
 	return;
 }
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.41/linux/arch/sparc64/config.in	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/config.in	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.87 2000/01/16 06:18:53 davem Exp $
+# $Id: config.in,v 1.89 2000/01/31 21:10:10 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.41/linux/arch/sparc64/defconfig	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc64/defconfig	Mon Jan 31 23:37:19 2000
@@ -292,6 +292,7 @@
 #
 # CONFIG_QUOTA is not set
 CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
 # CONFIG_ADFS_FS is not set
 CONFIG_AFFS_FS=m
 # CONFIG_HFS_FS is not set
@@ -307,10 +308,12 @@
 # CONFIG_JOLIET is not set
 CONFIG_MINIX_FS=m
 # CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
 CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_SYSV_FS=m
@@ -318,15 +321,16 @@
 CONFIG_UDF_FS=m
 # CONFIG_UDF_RW is not set
 CONFIG_UFS_FS=m
-CONFIG_UFS_FS_WRITE=y
+# CONFIG_UFS_FS_WRITE is not set
 
 #
 # Network File Systems
 #
 CONFIG_CODA_FS=m
 CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_SMB_FS=m
@@ -347,7 +351,6 @@
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SGI_PARTITION is not set
 CONFIG_SUN_PARTITION=y
 CONFIG_NLS=y
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/binfmt_elf32.c linux/arch/sparc64/kernel/binfmt_elf32.c
--- v2.3.41/linux/arch/sparc64/kernel/binfmt_elf32.c	Fri Jan 21 18:19:16 2000
+++ linux/arch/sparc64/kernel/binfmt_elf32.c	Mon Jan 31 23:37:19 2000
@@ -1,7 +1,7 @@
 /*
  * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
  *
- * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller	(davem@dm.cobaltmicro.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller	(davem@redhat.com)
  * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek	(jj@ultra.linux.cz)
  */
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/dtlb_backend.S linux/arch/sparc64/kernel/dtlb_backend.S
--- v2.3.41/linux/arch/sparc64/kernel/dtlb_backend.S	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/dtlb_backend.S	Mon Jan 31 23:37:19 2000
@@ -1,8 +1,8 @@
-/* $Id: dtlb_backend.S,v 1.8 1999/12/05 10:41:35 davem Exp $
+/* $Id: dtlb_backend.S,v 1.9 2000/01/31 04:59:12 davem Exp $
  * dtlb_backend.S: Back end to DTLB miss replacement strategy.
  *                 This is included directly into the trap table.
  *
- * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/dtlb_base.S linux/arch/sparc64/kernel/dtlb_base.S
--- v2.3.41/linux/arch/sparc64/kernel/dtlb_base.S	Tue Aug  4 16:03:35 1998
+++ linux/arch/sparc64/kernel/dtlb_base.S	Mon Jan 31 23:37:19 2000
@@ -1,8 +1,8 @@
-/* $Id: dtlb_base.S,v 1.4 1998/06/15 16:59:30 jj Exp $
+/* $Id: dtlb_base.S,v 1.5 2000/01/31 04:59:12 davem Exp $
  * dtlb_base.S:	Front end to DTLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
- * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S
--- v2.3.41/linux/arch/sparc64/kernel/dtlb_prot.S	Wed Mar 10 16:53:37 1999
+++ linux/arch/sparc64/kernel/dtlb_prot.S	Mon Jan 31 23:37:19 2000
@@ -1,8 +1,8 @@
-/* $Id: dtlb_prot.S,v 1.18 1999/03/02 15:42:14 jj Exp $
+/* $Id: dtlb_prot.S,v 1.19 2000/01/31 04:59:12 davem Exp $
  * dtlb_prot.S: DTLB protection trap strategy.
  *              This is included directly into the trap table.
  *
- * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.3.41/linux/arch/sparc64/kernel/ioctl32.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.74 2000/01/15 04:47:48 davem Exp $
+/* $Id: ioctl32.c,v 1.76 2000/01/31 21:10:15 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/iommu_common.c linux/arch/sparc64/kernel/iommu_common.c
--- v2.3.41/linux/arch/sparc64/kernel/iommu_common.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/iommu_common.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: iommu_common.c,v 1.2 1999/12/19 09:17:53 davem Exp $
+/* $Id: iommu_common.c,v 1.3 2000/01/28 13:41:59 jj Exp $
  * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/itlb_base.S linux/arch/sparc64/kernel/itlb_base.S
--- v2.3.41/linux/arch/sparc64/kernel/itlb_base.S	Wed Mar 10 16:53:37 1999
+++ linux/arch/sparc64/kernel/itlb_base.S	Mon Jan 31 23:37:19 2000
@@ -1,8 +1,8 @@
-/* $Id: itlb_base.S,v 1.7 1999/03/02 15:42:12 jj Exp $
+/* $Id: itlb_base.S,v 1.8 2000/01/31 04:59:12 davem Exp $
  * itlb_base.S:	Front end to ITLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
- * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c
--- v2.3.41/linux/arch/sparc64/kernel/pci_iommu.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/pci_iommu.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.7 1999/12/20 14:08:15 jj Exp $
+/* $Id: pci_iommu.c,v 1.8 2000/01/28 13:41:59 jj Exp $
  * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.3.41/linux/arch/sparc64/kernel/pci_psycho.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/pci_psycho.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.9 2000/01/11 23:38:32 davem Exp $
+/* $Id: pci_psycho.c,v 1.10 2000/01/28 13:42:00 jj Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.3.41/linux/arch/sparc64/kernel/pci_sabre.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/pci_sabre.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.10 2000/01/11 23:38:35 davem Exp $
+/* $Id: pci_sabre.c,v 1.11 2000/01/28 13:42:01 jj Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- v2.3.41/linux/arch/sparc64/kernel/sbus.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/sbus.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.6 1999/12/20 14:08:17 jj Exp $
+/* $Id: sbus.c,v 1.7 2000/01/28 13:41:58 jj Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.41/linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.70 2000/01/07 18:15:18 jj Exp $
+/* $Id: sparc64_ksyms.c,v 1.72 2000/01/28 13:41:59 jj Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -124,11 +124,6 @@
 EXPORT_SYMBOL_PRIVATE(write_unlock);
 #endif
 
-/* rw semaphores */
-EXPORT_SYMBOL_NOVERS(__down_read_failed);
-EXPORT_SYMBOL_NOVERS(__down_write_failed);
-EXPORT_SYMBOL_NOVERS(__rwsem_wake);
-
 /* Kernel wide locking */
 EXPORT_SYMBOL(kernel_flag);
 
@@ -168,6 +163,11 @@
 EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(local_bh_count);
 #endif
+
+/* rw semaphores */
+EXPORT_SYMBOL_NOVERS(__down_read_failed);
+EXPORT_SYMBOL_NOVERS(__down_write_failed);
+EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 
 /* Atomic counter implementation. */
 EXPORT_SYMBOL_PRIVATE(atomic_add);
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/starfire.c linux/arch/sparc64/kernel/starfire.c
--- v2.3.41/linux/arch/sparc64/kernel/starfire.c	Wed Dec 29 13:13:14 1999
+++ linux/arch/sparc64/kernel/starfire.c	Mon Jan 31 23:37:19 2000
@@ -1,7 +1,7 @@
-/* $Id: starfire.c,v 1.4 1999/09/21 14:35:25 davem Exp $
+/* $Id: starfire.c,v 1.5 2000/01/31 04:59:12 davem Exp $
  * starfire.c: Starfire/E10000 support.
  *
- * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
  */
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.3.41/linux/arch/sparc64/kernel/sys_sparc.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/sys_sparc.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.34 2000/01/21 11:39:06 jj Exp $
+/* $Id: sys_sparc.c,v 1.35 2000/01/29 07:40:12 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.41/linux/arch/sparc64/kernel/sys_sunos32.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.37 2000/01/21 11:39:03 jj Exp $
+/* $Id: sys_sunos32.c,v 1.38 2000/01/29 07:40:13 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.3.41/linux/arch/sparc64/kernel/systbls.S	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/kernel/systbls.S	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.66 2000/01/16 06:20:48 davem Exp $
+/* $Id: systbls.S,v 1.67 2000/01/29 16:41:21 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -48,7 +48,7 @@
 /*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64
 /*140*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
-	.word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
+	.word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
@@ -107,7 +107,7 @@
 /*130*/	.word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
 	.word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
 /*140*/	.word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
-	.word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
+	.word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_utrap_install
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c
--- v2.3.41/linux/arch/sparc64/lib/debuglocks.c	Fri Sep 10 23:57:28 1999
+++ linux/arch/sparc64/lib/debuglocks.c	Mon Jan 31 23:37:19 2000
@@ -1,7 +1,7 @@
-/* $Id: debuglocks.c,v 1.3 1999/09/10 10:40:50 davem Exp $
+/* $Id: debuglocks.c,v 1.4 2000/01/31 04:59:10 davem Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
- * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
  */
 
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/lib/memscan.S linux/arch/sparc64/lib/memscan.S
--- v2.3.41/linux/arch/sparc64/lib/memscan.S	Tue Aug  4 16:03:35 1998
+++ linux/arch/sparc64/lib/memscan.S	Mon Jan 31 23:37:19 2000
@@ -1,8 +1,8 @@
-/* $Id: memscan.S,v 1.2 1998/05/21 14:42:22 jj Exp $
+/* $Id: memscan.S,v 1.3 2000/01/31 04:59:10 davem Exp $
  * memscan.S: Optimized memscan for Sparc64.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
  */
 
 #define HI_MAGIC	0x8080808080808080
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/mm/Makefile linux/arch/sparc64/mm/Makefile
--- v2.3.41/linux/arch/sparc64/mm/Makefile	Tue Aug  4 16:03:35 1998
+++ linux/arch/sparc64/mm/Makefile	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 1998/07/26 03:02:54 davem Exp $
+# $Id: Makefile,v 1.6 2000/01/31 01:30:49 davem Exp $
 # Makefile for the linux Sparc64-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -14,6 +14,6 @@
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
 
 O_TARGET := mm.o
-O_OBJS   := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o
+O_OBJS   := ultra.o fault.o init.o generic.o extable.o modutil.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/mm/asyncd.c linux/arch/sparc64/mm/asyncd.c
--- v2.3.41/linux/arch/sparc64/mm/asyncd.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/mm/asyncd.c	Wed Dec 31 16:00:00 1969
@@ -1,283 +0,0 @@
-/*  $Id: asyncd.c,v 1.12 2000/01/21 11:39:13 jj Exp $
- *  The asyncd kernel daemon. This handles paging on behalf of 
- *  processes that receive page faults due to remote (async) memory
- *  accesses. 
- *
- *  Idea and skeleton code courtesy of David Miller (bless his cotton socks)
- *
- *  Implemented by tridge
- */
-
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/swap.h>
-#include <linux/fs.h>
-#include <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/signal.h>
-
-#include <asm/dma.h>
-#include <asm/system.h> /* for cli()/sti() */
-#include <asm/segment.h> /* for memcpy_to/fromfs */
-#include <asm/bitops.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-
-#define DEBUG 0
-
-#define WRITE_LIMIT 100
-#define LOOP_LIMIT 200
-
-static struct {
-	int faults, read, write, success, failure, errors;
-} stats;
-
-/* 
- * The wait queue for waking up the async daemon:
- */
-static DECLARE_WAIT_QUEUE_HEAD(asyncd_wait);
-
-struct async_job {
-	volatile struct async_job *next;
-	int taskid;
-	struct mm_struct *mm;
-	unsigned long address;
-	int write;
-	void (*callback)(int,unsigned long,int,int);
-};
-
-static volatile struct async_job *async_queue = NULL;
-static volatile struct async_job *async_queue_end = NULL;
-
-static void add_to_async_queue(int taskid,
-			       struct mm_struct *mm,
-			       unsigned long address,
-			       int write,
-			       void (*callback)(int,unsigned long,int,int))
-{
-	struct async_job *a = kmalloc(sizeof(*a),GFP_ATOMIC);
-
-	if (!a) {
-		printk("ERROR: out of memory in asyncd\n");
-		a->callback(taskid,address,write,1);
-		return;
-	}
-
-	if (write)
-		stats.write++;
-	else
-		stats.read++;
-
-	a->next = NULL;
-	a->taskid = taskid;
-	a->mm = mm;
-	a->address = address;
-	a->write = write;
-	a->callback = callback;
-
-	if (!async_queue) {
-		async_queue = a;
-	} else {
-		async_queue_end->next = a;
-	}
-	async_queue_end = a;
-}
-
-
-void async_fault(unsigned long address, int write, int taskid,
-		 void (*callback)(int,unsigned long,int,int))
-{
-#warning Need some fixing here... -DaveM
-	struct task_struct *tsk = current /* XXX task[taskid] */;
-	struct mm_struct *mm = tsk->mm;
-
-	stats.faults++;
-
-#if 0
-	printk("paging in %x for task=%d\n",address,taskid);
-#endif
-
-	add_to_async_queue(taskid, mm, address, write, callback);
-	wake_up(&asyncd_wait);  
-	mark_bh(TQUEUE_BH);
-}
-
-static int fault_in_page(int taskid,
-			 struct vm_area_struct *vma,
-			 unsigned long address, int write)
-{
-	static unsigned last_address;
-	static int last_task, loop_counter;
-	siginfo_t info;
-#warning Need some fixing here... -DaveM
-	struct task_struct *tsk = current /* XXX task[taskid] */;
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-
-	if (!tsk || !tsk->mm)
-		return 1;
-
-	if (!vma || (write && !(vma->vm_flags & VM_WRITE)))
-	  goto bad_area;
-	if (vma->vm_start > address)
-	  goto bad_area;
-
-	if (address == last_address && taskid == last_task) {
-		loop_counter++;
-	} else {
-		loop_counter = 0;
-		last_address = address; 
-		last_task = taskid;
-	}
-
-	if (loop_counter == WRITE_LIMIT && !write) {
-		printk("MSC bug? setting write request\n");
-		stats.errors++;
-		write = 1;
-	}
-
-	if (loop_counter == LOOP_LIMIT) {
-		printk("MSC bug? failing request\n");
-		stats.errors++;
-		return 1;
-	}
-
-	pgd = pgd_offset(vma->vm_mm, address);
-	pmd = pmd_alloc(pgd,address);
-	if(!pmd)
-		goto no_memory;
-	pte = pte_alloc(pmd, address);
-	if(!pte)
-		goto no_memory;
-	if(!pte_present(*pte)) {
-		handle_mm_fault(tsk, vma, address, write);
-		goto finish_up;
-	}
-	set_pte(pte, pte_mkyoung(*pte));
-	flush_tlb_page(vma, address);
-	if(!write)
-		goto finish_up;
-	if(pte_write(*pte)) {
-		set_pte(pte, pte_mkdirty(*pte));
-		flush_tlb_page(vma, address);
-		goto finish_up;
-	}
-	handle_mm_fault(tsk, vma, address, write);
-
-	/* Fall through for do_wp_page */
-finish_up:
-	stats.success++;
-	return 0;
-
-no_memory:
-	stats.failure++;
-	oom(tsk);
-	return 1;
-	
-bad_area:	  
-	stats.failure++;
-	info.si_signo = SIGSEGV;
-	info.si_errno = 0;
-	info.si_code = SEGV_MAPERR;
-	info.si_addr = (void *)address;
-	info.si_trapno = 0;
-	send_sig_info(SIGSEGV, &info, tsk);
-	return 1;
-}
-
-
-/* Note the semaphore operations must be done here, and _not_
- * in async_fault().
- */
-static void run_async_queue(void)
-{
-	int ret;
-	unsigned flags;
-
-	while (async_queue) {
-		volatile struct async_job *a;
-		struct mm_struct *mm;
-		struct vm_area_struct *vma;
-
-		save_flags(flags); cli();
-		a = async_queue;
-		async_queue = async_queue->next;
-		restore_flags(flags);
-
-		mm = a->mm;
-
-		down(&mm->mmap_sem);
-		vma = find_vma(mm, a->address);
-		ret = fault_in_page(a->taskid,vma,a->address,a->write);
-#if DEBUG
-		printk("fault_in_page(task=%d addr=%x write=%d) = %d\n",
-		       a->taskid,a->address,a->write,ret);
-#endif
-		a->callback(a->taskid,a->address,a->write,ret);
-		up(&mm->mmap_sem);
-		kfree_s((void *)a,sizeof(*a));
-	}
-}
-
-
-#if CONFIG_AP1000
-static void asyncd_info(void)
-{
-	printk("CID(%d) faults: total=%d  read=%d  write=%d  success=%d fail=%d err=%d\n",
-	       mpp_cid(),stats.faults, stats.read, stats.write, stats.success,
-	       stats.failure, stats.errors);
-}
-#endif
-
-
-/*
- * The background async daemon.
- * Started as a kernel thread from the init process.
- */
-int asyncd(void *unused)
-{
-	current->session = 1;
-	current->pgrp = 1;
-	sprintf(current->comm, "asyncd");
-	
-	sigfillset(&current->blocked); /* block all signals */
-	recalc_sigpending(current);
-  
-	/* Give asyncd a realtime priority. */
-	current->policy = SCHED_FIFO;
-	current->priority = 32;  /* Fixme --- we need to standardise our
-				    namings for POSIX.4 realtime scheduling
-				    priorities.  */
-  
-	printk("Started asyncd\n");
-
-#if CONFIG_AP1000
-	bif_add_debug_key('a',asyncd_info,"stats on asyncd");
-#endif
-
-	while (1) {
-		unsigned flags;
-
-		save_flags(flags); cli();
-
-		while (!async_queue) {
-			spin_lock(&current->sigmask_lock);
-			flush_signals(current);
-			spin_unlock(&current->sigmask_lock);
-			interruptible_sleep_on(&asyncd_wait);
-			__sti(); cli(); /* acquire gloabl_irq_lock */
-		}
-
-		restore_flags(flags);
-
-		run_async_queue();
-	}
-}
-
diff -u --recursive --new-file v2.3.41/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.3.41/linux/arch/sparc64/solaris/misc.c	Fri Jan 28 15:09:07 2000
+++ linux/arch/sparc64/solaris/misc.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.20 2000/01/12 02:59:26 davem Exp $
+/* $Id: misc.c,v 1.21 2000/01/29 07:40:15 davem Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.3.41/linux/drivers/Makefile linux/drivers/Makefile
--- v2.3.41/linux/drivers/Makefile	Fri Jan 21 18:19:16 2000
+++ linux/drivers/Makefile	Mon Jan 31 23:37:19 2000
@@ -11,7 +11,7 @@
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o ieee1394 \
 				macintosh video dio zorro fc4 usb \
-				nubus tc ap1000 atm pcmcia i2c telephony
+				nubus tc atm pcmcia i2c telephony
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -135,10 +135,6 @@
 ifdef CONFIG_ATM
 SUB_DIRS += atm
 MOD_SUB_DIRS += atm
-endif
-
-ifeq ($(CONFIG_AP1000),y)
-SUB_DIRS += ap1000
 endif
 
 ifeq ($(CONFIG_FC4),y)
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/Makefile linux/drivers/ap1000/Makefile
--- v2.3.41/linux/drivers/ap1000/Makefile	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,29 +0,0 @@
-# File: drivers/ap1000/Makefile
-#
-# Makefile for the AP1000 drivers
-#
-
-L_TARGET := ap1000.a
-L_OBJS   := bif.o apfddi.o mac.o plc.o ringbuf.o
-
-ifeq ($(CONFIG_APBLOCK),y)
-L_OBJS += ap.o
-else
-  ifeq ($(CONFIG_APBLOCK),m)
-  M_OBJS += ap.o
-  endif
-endif
-
-ifeq ($(CONFIG_DDV),y)
-L_OBJS += ddv.o ddv_util.o
-else
-  ifeq ($(CONFIG_DDV),m)
-  M_OBJS += ddv.o ddv_util.o
-  endif
-endif
-
-include $(TOPDIR)/Rules.make
-
-clean:
-	rm -f core *.o *.a *.s
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/am79c830.h linux/drivers/ap1000/am79c830.h
--- v2.3.41/linux/drivers/ap1000/am79c830.h	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/am79c830.h	Wed Dec 31 16:00:00 1969
@@ -1,276 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Definitions for the AM79C830 FORMAC (Fiber Optic Ring MAC) chip.
- */
-
-typedef int	formac_reg;
-
-struct formac {
-    formac_reg	cmdreg1;	/* command register 1 */
-    formac_reg	cmdreg2;	/* command register 2 */
-#define st1u	cmdreg1		/* status reg 1, upper */
-#define st1l	cmdreg2		/* status reg 1, lower */
-    formac_reg	st2u;		/* status reg 2, upper */
-    formac_reg	st2l;		/* status reg 2, lower */
-    formac_reg	imsk1u;		/* interrupt mask 1, upper */
-    formac_reg	imsk1l;		/* interrupt mask 1, lower */
-    formac_reg	imsk2u;		/* interrupt mask 2, upper */
-    formac_reg	imsk2l;		/* interrupt mask 2, lower */
-    formac_reg	said;		/* short address, individual */
-    formac_reg	laim;		/* long adrs, indiv, MS word */
-    formac_reg	laic;		/* long adrs, indiv, middle word */
-    formac_reg	lail;		/* long adrs, indiv, LS word */
-    formac_reg	sagp;		/* short address, group */
-    formac_reg	lagm;		/* short adrs, group, MS word */
-    formac_reg	lagc;		/* short adrs, group, middle word */
-    formac_reg	lagl;		/* short adrs, group, LS word */
-    formac_reg	mdreg1;		/* mode reg 1 */
-    formac_reg	stmchn;		/* state machine reg */
-    formac_reg	mir1;		/* MAC information reg, upper */
-    formac_reg	mir0;		/* MAC information reg, lower */
-    formac_reg	tmax;		/* TMax value (2's-comp) */
-    formac_reg	tvx;		/* TVX value (2's-comp) */
-    formac_reg	trt;		/* TRT timer value */
-    formac_reg	tht;		/* THT timer value */
-    formac_reg	tneg;		/* current TNeg (2's-comp) */
-    formac_reg	tmrs;		/* extra bits of tneg, trt, tht; late count */
-    formac_reg	treq0;		/* our TReq (2's-comp), lower */
-    formac_reg	treq1;		/* our TReq (2's-comp), upper */
-    formac_reg	pri0;		/* priority reg for async queue 0 */
-    formac_reg	pri1;		/* priority reg for async queue 1 */
-    formac_reg	pri2;		/* priority reg for async queue 2 */
-    formac_reg	tsync;		/* TSync value (2's-comp) */
-    formac_reg	mdreg2;		/* mode reg 2 */
-    formac_reg	frmthr;		/* frame threshold reg */
-    formac_reg	eacb;		/* end address of claim/beacon area */
-    formac_reg	earv;		/* end address of receive area */
-    formac_reg	eas;		/* end address of sync queue */
-    formac_reg	eaa0;		/* end address of async queue 0 */
-    formac_reg	eaa1;		/* end address of async queue 1 */
-    formac_reg	eaa2;		/* end address of async queue 2 */
-    formac_reg	sacl;		/* start address of claim frame */
-    formac_reg	sabc;		/* start address of beacon frame */
-    formac_reg	wpxsf;		/* write pointer, special frames */
-    formac_reg	rpxsf;		/* read pointer, special frames */
-    formac_reg	dummy1;		/* not used */
-    formac_reg	rpr;		/* read pointer, receive */
-    formac_reg	wpr;		/* write pointer, receive */
-    formac_reg	swpr;		/* shadow write pointer, receive */
-    formac_reg	wpxs;		/* write pointer, sync queue */
-    formac_reg	wpxa0;		/* write pointer, async queue 0 */
-    formac_reg	wpxa1;		/* write pointer, async queue 1 */
-    formac_reg	wpxa2;		/* write pointer, async queue 2 */
-    formac_reg	swpxs;		/* shadow write pointer, sync queue */
-    formac_reg	swpxa0;		/* shadow write pointer, async queue 0 */
-    formac_reg	swpxa1;		/* shadow write pointer, async queue 1 */
-    formac_reg	swpxa2;		/* shadow write pointer, async queue 2 */
-    formac_reg	rpxs;		/* read pointer, sync queue */
-    formac_reg	rpxa0;		/* read pointer, async queue 0 */
-    formac_reg	rpxa1;		/* read pointer, async queue 1 */
-    formac_reg	rpxa2;		/* read pointer, async queue 2 */
-    formac_reg	marr;		/* memory address for random reads */
-    formac_reg	marw;		/* memory address for random writes */
-    formac_reg	mdru;		/* memory data register, upper */
-    formac_reg	mdrl;		/* memory data register, lower */
-    formac_reg	tmsync;		/* TSync timer value */
-    formac_reg	fcntr;		/* frame counter */
-    formac_reg	lcntr;		/* lost counter */
-    formac_reg	ecntr;		/* error counter */
-};
-
-/* Values for cmdreg1 */
-#define C1_SOFTWARE_RESET	1
-#define C1_IRMEMWI		2
-#define C1_IRMEMWO		3
-#define C1_IDLE_LISTEN		4
-#define C1_CLAIM_LISTEN		5
-#define C1_BEACON_LISTEN	6
-#define C1_LOAD_TVX		7
-#define C1_SEND_NR_TOKEN	0x0c
-#define C1_SEND_R_TOKEN		0x0d
-#define C1_ENTER_SI_MODE	0x0e
-#define C1_EXIT_SI_MODE		0x0f
-#define C1_CLR_SYNCQ_LOCK	0x11
-#define C1_CLR_ASYNCQ0_LOCK	0x12
-#define C1_CLR_ASYNCQ1_LOCK	0x14
-#define C1_CLR_ASYNCQ2_LOCK	0x18
-#define C1_CLR_RECVQ_LOCK	0x20
-#define C1_CLR_ALL_LOCKS	0x3f
-
-/* Values for cmdreg2 */
-#define C2_XMIT_SYNCQ		1
-#define C2_XMIT_ASYNCQ0		2
-#define C2_XMIT_ASYNCQ1		4
-#define C2_XMIT_ASYNCQ2		8
-#define C2_ABORT_XMIT		0x10
-#define C2_RESET_XMITQS		0x20
-#define C2_SET_TAG		0x30
-#define C2_EN_RECV_FRAME	0x40
-
-/* Bits in (st1u << 16) + st1l (and (imsk1u << 16) + imsk1l) */
-#define S1_XMIT_ABORT		0x80000000
-#define S1_XABORT_ASYNC2	0x40000000
-#define S1_XABORT_ASYNC1	0x20000000
-#define S1_XABORT_ASYNC0	0x10000000
-#define S1_XABORT_SYNC		0x08000000
-#define S1_XBUF_FULL_SYNC	0x04000000
-#define S1_XBUF_FULL_ASYNC	0x02000000
-#define S1_XDONE_SYNC		0x01000000
-#define S1_END_CHAIN_ASYNC2	0x00800000
-#define S1_END_CHAIN_ASYNC1	0x00400000
-#define S1_END_CHAIN_ASYNC0	0x00200000
-#define S1_END_CHAIN_SYNC	0x00100000
-#define S1_END_FRAME_ASYNC2	0x00080000
-#define S1_END_FRAME_ASYNC1	0x00040000
-#define S1_END_FRAME_ASYNC0	0x00020000
-#define S1_END_FRAME_SYNC	0x00010000
-#define S1_BUF_UNDERRUN_ASYNC2	0x00008000
-#define S1_BUF_UNDERRUN_ASYNC1	0x00004000
-#define S1_BUF_UNDERRUN_ASYNC0	0x00002000
-#define S1_BUF_UNDERRUN_SYNC	0x00001000
-#define S1_PAR_ERROR_ASYNC2	0x00000800
-#define S1_PAR_ERROR_ASYNC1	0x00000400
-#define S1_PAR_ERROR_ASYNC0	0x00000200
-#define S1_PAR_ERROR_SYNC	0x00000100
-#define S1_XINSTR_FULL_ASYNC2	0x00000080
-#define S1_XINSTR_FULL_ASYNC1	0x00000040
-#define S1_XINSTR_FULL_ASYNC0	0x00000020
-#define S1_XINSTR_FULL_SYNC	0x00000010
-#define S1_QUEUE_LOCK_ASYNC2	0x00000008
-#define S1_QUEUE_LOCK_ASYNC1	0x00000004
-#define S1_QUEUE_LOCK_ASYNC0	0x00000002
-#define S1_QUEUE_LOCK_SYNC	0x00000001
-
-/* Bits in (st2u << 16) + st2l (and (imsk2u << 16) + imsk2l) */
-#define S2_RECV_COMPLETE	0x80000000
-#define S2_RECV_BUF_EMPTY	0x40000000
-#define S2_RECV_ABORT		0x20000000
-#define S2_RECV_BUF_FULL	0x10000000
-#define S2_RECV_FIFO_OVF	0x08000000
-#define S2_RECV_FRAME		0x04000000
-#define S2_RECV_FRCT_OVF	0x02000000
-#define S2_NP_SIMULT_LOAD	0x01000000
-#define S2_ERR_SPECIAL_FR	0x00800000
-#define S2_CLAIM_STATE		0x00400000
-#define S2_MY_CLAIM		0x00200000
-#define S2_HIGHER_CLAIM		0x00100000
-#define S2_LOWER_CLAIM		0x00080000
-#define S2_BEACON_STATE		0x00040000
-#define S2_MY_BEACON		0x00020000
-#define S2_OTHER_BEACON		0x00010000
-#define S2_RING_OP		0x00008000
-#define S2_MULTIPLE_DA		0x00004000
-#define S2_TOKEN_ERR		0x00002000
-#define S2_TOKEN_ISSUED		0x00001000
-#define S2_TVX_EXP		0x00000800
-#define S2_TRT_EXP		0x00000400
-#define S2_MISSED_FRAME		0x00000200
-#define S2_ADDRESS_DET		0x00000100
-#define S2_PHY_INVALID		0x00000080
-#define S2_LOST_CTR_OVF		0x00000040
-#define S2_ERR_CTR_OVF		0x00000020
-#define S2_FRAME_CTR_OVF	0x00000010
-#define S2_SHORT_IFG		0x00000008
-#define S2_DUPL_CLAIM		0x00000004
-#define S2_TRT_EXP_RECOV	0x00000002
-
-/* Bits in mdreg1 */
-#define M1_SINGLE_FRAME		0x8000
-#define M1_MODE			0x7000
-#define M1_MODE_INITIALIZE	0x0000
-#define M1_MODE_MEMORY		0x1000
-#define M1_MODE_ONLINE_SP	0x2000
-#define M1_MODE_ONLINE		0x3000
-#define M1_MODE_INT_LOOP	0x4000
-#define M1_MODE_EXT_LOOP	0x7000
-#define M1_SHORT_ADRS		0x0800
-#define M1_ADDET		0x0700
-#define M1_ADDET_NORM		0x0000
-#define M1_ADDET_METOO		0x0100
-#define M1_ADDET_NSA_NOTME	0x0200
-#define M1_ADDET_NSA		0x0300
-#define M1_ADDET_DISABLE_RECV	0x0400
-#define M1_ADDET_LIM_PROMISC	0x0600
-#define M1_ADDET_PROMISC	0x0700
-#define M1_SELECT_RA		0x0080
-#define M1_DISABLE_CARRY	0x0040
-#define M1_EXT_GRP		0x0030
-#define M1_EXT_GRP_MYGRP	0x0000
-#define M1_EXT_GRP_SOFT		0x0010
-#define M1_EXT_GRP_UPPER24	0x0020
-#define M1_EXT_GRP_UPPER16	0x0030
-#define M1_LOCK_XMIT_QS		0x0008
-#define M1_FULL_DUPLEX		0x0004
-#define M1_XMTINH_PIN		0x0002
-
-/* Bits in mdreg2 */
-#define M2_TAGMODE		0x8000
-#define M2_STRIP_FCS		0x4000
-#define M2_CHECK_PARITY		0x2000
-#define M2_EVEN_PARITY		0x1000
-#define M2_LSB_FIRST		0x0800
-#define M2_RCV_BYTE_BDRY_MASK	0x0600
-#define M2_RCV_BYTE_BDRY	0x0200
-#define M2_ENABLE_HSREQ		0x0100
-#define M2_ENABLE_NPDMA		0x0080
-#define M2_SYNC_NPDMA		0x0040
-#define M2_SYMBOL_CTRL		0x0020
-#define M2_RECV_BAD_FRAMES	0x0010
-#define M2_AFULL_MASK		0x000f
-#define M2_AFULL		0x0001
-
-/* Bits in stmchn */
-#define SM_REV_MASK		0xe000
-#define SM_REV			0x2000
-#define SM_SEND_IMM_MODE	0x1000
-#define SM_TOKEN_MODE		0x0c00
-#define SM_TOKEN_MODE_NR	0x0000
-#define SM_TOKEN_MODE_ENTER_R	0x0400
-#define SM_TOKEN_MODE_ENTER_NR	0x0800
-#define SM_TOKEN_MODE_R		0x0c00
-#define SM_RCV_STATE		0x0380
-#define SM_XMIT_STATE		0x0070
-#define SM_MDR_PENDING		0x0008
-#define SM_MDR_TAG		0x0004
-
-/* Bits in transmit descriptor */
-#define TD_MORE			0x80000000
-#define TD_MAGIC		0x40000000
-#define TD_BYTE_BDRY_MASK	0x18000000
-#define TD_BYTE_BDRY_1		0x08000000
-#define TD_XMIT_DONE		0x04000000
-#define TD_NO_FCS		0x02000000
-#define TD_XMIT_ABORT		0x01000000
-#define TD_BYTE_BDRY_LG		27
-
-/* Bits in pointer in buffer memory (nontag mode) */
-#define PT_MAGIC		0xa0000000
-
-/* Bits in receive status word */
-#define RS_VALID		0x80000000
-#define RS_ABORTED		0x40000000
-#define RS_SRC_ROUTE		0x10000000
-#define RS_E_INDIC		0x08000000
-#define RS_A_INDIC		0x04000000
-#define RS_C_INDIC		0x02000000
-#define RS_ERROR		0x01000000
-#define RS_ADDR_MATCH		0x00800000
-#define RS_FRAME_TYPE		0x00700000
-#define RS_FT_SMT		0x00000000
-#define RS_FT_LLC		0x00100000
-#define RS_FT_IMPL		0x00200000
-#define RS_FT_MAC		0x00400000
-#define RS_FT_LLC_SYNC		0x00500000
-#define RS_FT_IMPL_SYNC		0x00600000
-#define RS_BYTE_BDRY_MASK	0x00030000
-#define RS_BYTE_BDRY		0x00010000
-#define RS_BYTE_BDRY_LG		16
-
-#define RS_LENGTH		0x0000ffff
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/am79c864.h linux/drivers/ap1000/am79c864.h
--- v2.3.41/linux/drivers/ap1000/am79c864.h	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/am79c864.h	Wed Dec 31 16:00:00 1969
@@ -1,162 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Definitions for Am79c864 PLC (Physical Layer Controller)
- */
-
-typedef int	plc_reg;
-
-struct plc {
-    plc_reg	ctrl_a;
-    plc_reg	ctrl_b;
-    plc_reg	intr_mask;
-    plc_reg	xmit_vector;
-    plc_reg	vec_length;
-    plc_reg	le_threshold;
-    plc_reg	c_min;
-    plc_reg	tl_min;
-    plc_reg	tb_min;
-    plc_reg	t_out;
-    plc_reg	dummy1;
-    plc_reg	lc_length;
-    plc_reg	t_scrub;
-    plc_reg	ns_max;
-    plc_reg	tpc_load;
-    plc_reg	tne_load;
-    plc_reg	status_a;
-    plc_reg	status_b;
-    plc_reg	tpc;
-    plc_reg	tne;
-    plc_reg	clk_div;
-    plc_reg	bist_sig;
-    plc_reg	rcv_vector;
-    plc_reg	intr_event;
-    plc_reg	viol_sym_ct;
-    plc_reg	min_idle_ct;
-    plc_reg	link_err_ct;
-};
-
-/* Bits in ctrl_a */
-#define CA_NOISE_TIMER		0x4000
-#define CA_TNE_16BIT		0x2000
-#define CA_TPC_16BIT		0x1000
-#define CA_REQ_SCRUB		0x0800
-#define CA_VSYM_INTR_MODE	0x0200
-#define CA_MINI_INTR_MODE	0x0100
-#define CA_LOOPBACK		0x0080
-#define CA_FOT_OFF		0x0040
-#define CA_EB_LOOP		0x0020
-#define CA_LM_LOOP		0x0010
-#define CA_BYPASS		0x0008
-#define CA_REM_LOOP		0x0004
-#define CA_RF_DISABLE		0x0002
-#define CA_RUN_BIST		0x0001
-
-/* Bits in ctrl_b */
-#define CB_CONFIG_CTRL		0x8000
-#define CB_MATCH_LS		0x7800
-#define CB_MATCH_LS_ANY		0x0000
-#define CB_MATCH_LS_QLS		0x4000
-#define CB_MATCH_LS_MLS		0x2000
-#define CB_MATCH_LS_HLS		0x1000
-#define CB_MATCH_LS_ILS		0x0800
-#define CB_MAINT_LS		0x0700
-#define CB_MAINT_LS_QLS		0x0000
-#define CB_MAINT_LS_ILS		0x0100
-#define CB_MAINT_LS_HLS		0x0200
-#define CB_MAINT_LS_MLS		0x0300
-#define CB_MAINT_LS_PDR		0x0600
-#define CB_CLASS_S		0x0080
-#define CB_PC_LCT		0x0060
-#define CB_PC_LCT_NONE		0x0000
-#define CB_PC_LCT_PDR		0x0020
-#define CB_PC_LCT_IDLE		0x0040
-#define CB_PC_LCT_LOOP		0x0060
-#define CB_PC_JOIN		0x0010
-#define CB_LONG_LCT		0x0008
-#define CB_PC_MAINT		0x0004
-#define CB_PCM_CTRL		0x0003
-#define CB_PC_START		0x0001
-#define CB_PC_TRACE		0x0002
-#define CB_PC_STOP		0x0003
-
-/* Bits in status_a */
-#define SA_SIG_DETECT		0x0400
-#define SA_PREV_LS		0x0300
-#define SA_PREV_LS_QLS		0x0000
-#define SA_PREV_LS_MLS		0x0100
-#define SA_PREV_LS_HLS		0x0200
-#define SA_PREV_LS_ILS		0x0300
-#define SA_LINE_ST		0x00e0
-#define SA_LINE_ST_NLS		0x0000
-#define SA_LINE_ST_ALS		0x0020
-#define SA_LINE_ST_ILS4		0x0060
-#define SA_LINE_ST_QLS		0x0080
-#define SA_LINE_ST_MLS		0x00a0
-#define SA_LINE_ST_HLS		0x00c0
-#define SA_LINE_ST_ILS		0x00e0
-#define SA_LSM_STATE		0x0010
-#define SA_UNKN_LINE_ST		0x0008
-#define SA_SYM_PAIR_CTR		0x0007
-
-/* Bits in status_b */
-#define SB_RF_STATE		0xc000
-#define SB_RF_STATE_REPEAT	0x0000
-#define SB_RF_STATE_IDLE	0x4000
-#define SB_RF_STATE_HALT1	0x8000
-#define SB_RF_STATE_HALT2	0xc000
-#define SB_PCI_STATE		0x3000
-#define SB_PCI_STATE_REMOVED	0x0000
-#define SB_PCI_STATE_INS_SCR	0x1000
-#define SB_PCI_STATE_REM_SCR	0x2000
-#define SB_PCI_STATE_INSERTED	0x3000
-#define SB_PCI_SCRUB		0x0800
-#define SB_PCM_STATE		0x0780
-#define SB_PCM_STATE_OFF	0x0000
-#define SB_PCM_STATE_BREAK	0x0080
-#define SB_PCM_STATE_TRACE	0x0100
-#define SB_PCM_STATE_CONNECT	0x0180
-#define SB_PCM_STATE_NEXT	0x0200
-#define SB_PCM_STATE_SIGNAL	0x0280
-#define SB_PCM_STATE_JOIN	0x0300
-#define SB_PCM_STATE_VERIFY	0x0380
-#define SB_PCM_STATE_ACTIVE	0x0400
-#define SB_PCM_STATE_MAIN	0x0480
-#define SB_PCM_SIGNALING	0x0040
-#define SB_LSF			0x0020
-#define SB_RCF			0x0010
-#define SB_TCF			0x0008
-#define SB_BREAK_REASON		0x0007
-#define SB_BREAK_REASON_NONE	0x0000
-#define SB_BREAK_REASON_START	0x0001
-#define SB_BREAK_REASON_T_OUT	0x0002
-#define SB_BREAK_REASON_NS_MAX	0x0003
-#define SB_BREAK_REASON_QLS	0x0004
-#define SB_BREAK_REASON_ILS	0x0005
-#define SB_BREAK_REASON_HLS	0x0006
-
-/* Bits in intr_event and intr_mask */
-#define IE_NP_ERROR		0x8000
-#define IE_SIGNAL_OFF		0x4000
-#define IE_LE_CTR		0x2000
-#define IE_MINI_CTR		0x1000
-#define IE_VSYM_CTR		0x0800
-#define IE_PHY_INVALID		0x0400
-#define IE_EBUF_ERR		0x0200
-#define IE_TNE_EXP		0x0100
-#define IE_TPC_EXP		0x0080
-#define IE_PCM_ENABLED		0x0040
-#define IE_PCM_BREAK		0x0020
-#define IE_SELF_TEST		0x0010
-#define IE_TRACE_PROP		0x0008
-#define IE_PCM_CODE		0x0004
-#define IE_LS_MATCH		0x0002
-#define IE_PARITY_ERR		0x0001
-
-/* Correct value for BIST signature */
-#define BIST_CORRECT		0x6ecd
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/ap.c linux/drivers/ap1000/ap.c
--- v2.3.41/linux/drivers/ap1000/ap.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ap1000/ap.c	Wed Dec 31 16:00:00 1969
@@ -1,307 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* 
- * ap.c - Single AP1000 block driver.
- *
- * (C) dwalsh, Pious project, DCS, ANU 1996
- *
- * This block driver is designed to simply to perform
- * io operations to the hosts file system. 
- *
- * Heavily modified by tridge
- *
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/ap1000/apservice.h>
-
-#define AP_DEBUG 0
-
-#define MAJOR_NR APBLOCK_MAJOR
-#define AP_DRIVER 1
-#include <linux/blk.h>
-
-#define NUM_APDEVS 8
-#define MAX_REQUESTS 1
-
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-static int ap_blocksizes[NUM_APDEVS];
-static int ap_length[NUM_APDEVS];
-static int ap_fds[NUM_APDEVS];
-
-#define SECTOR_BLOCK_SHIFT 9
-#define AP_BLOCK_SHIFT 12 /* 4k blocks */
-#define AP_BLOCK_SIZE (1<<AP_BLOCK_SHIFT)
-
-static volatile int request_count = 0;
-
-static void ap_release(struct inode * inode, struct file * filp)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-static void ap_request(request_queue_t * q)
-{
-  struct cap_request creq;
-  unsigned int minor;
-  int offset, len;
-  struct request *req;
-
-  if (request_count >= MAX_REQUESTS) return;
-
-repeat:  
-
-  if (!CURRENT) {
-    return;
-  }
-
-  if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) {
-    panic(DEVICE_NAME ": request list destroyed");
-  }
-  if (CURRENT->bh) {
-    if (!buffer_locked(CURRENT->bh)) {
-      panic(DEVICE_NAME ": block not locked");
-    }
-  }
-
-  req = CURRENT;
-
-  minor = MINOR(req->rq_dev);
-
-  if (minor >= NUM_APDEVS) {
-    printk("apblock: request for invalid minor %d\n",minor);
-    end_request(0);
-    goto repeat;
-  }
-
-  offset = req->sector;
-  len = req->current_nr_sectors;
-
-  if ((offset + len) > ap_length[minor]) {
-    printk("apblock: request for invalid sectors %d -> %d\n",
-	   offset,offset+len);
-    end_request(0);
-    goto repeat;
-  }
-
-  if (ap_fds[minor] == -1) {
-    printk("apblock: minor %d not open\n",minor);
-    end_request(0);
-    goto repeat;
-  }
-
-  /* convert to our units */
-  offset <<= SECTOR_BLOCK_SHIFT;
-  len <<= SECTOR_BLOCK_SHIFT;
-  
-  /* setup a request for the host */
-  creq.cid = mpp_cid();
-  creq.size = sizeof(creq);
-  creq.header = 0;
-  creq.data[0] = (int)(req);
-  creq.data[1] = ap_fds[minor];
-  creq.data[2] = offset;
-  creq.data[3] = len;
-
-  switch (req->cmd) {
-  case READ:
-#if AP_DEBUG
-    printk("apblock: read req=0x%x len=%d offset=%d\n",
-	   req,len,offset);
-#endif
-    creq.type = REQ_BREAD;
-    if (bif_queue(&creq,0,0)) {
-      return;
-    }
-    break;
-
-  case WRITE:
-#if AP_DEBUG
-    printk("apblock: write req=0x%x len=%d offset=%d\n",
-	   req,len,offset);
-#endif
-    creq.type = REQ_BWRITE;
-    creq.size += len;
-    if (bif_queue_nocopy(&creq,req->buffer,creq.size - sizeof(creq))) {
-      return;
-    }
-    break;
-
-  default:
-    printk("apblock: unknown ap op %d\n",req->cmd);
-    end_request(0);
-    return;
-  }
-
-  if (++request_count < MAX_REQUESTS)
-    goto repeat;
-}
-
-/* this is called by ap1000/bif.c when a read/write has completed */
-void ap_complete(struct cap_request *creq)
-{  
-#if AP_DEBUG
-  struct request *req = (struct request *)(creq->data[0]);
-
-  printk("request 0x%x complete\n",req);
-#endif
-  end_request(1);
-  request_count--;
-  ap_request(NULL);
-}
-
-
-/* this is called by ap1000/bif.c to find a buffer to put a BREAD into 
- using DMA */
-char *ap_buffer(struct cap_request *creq)
-{  
-  struct request *req = (struct request *)(creq->data[0]);
-
-  return(req->buffer);
-}
-
-
-static int ap_open(struct inode * inode, struct file * filp)
-{
-  struct cap_request creq;
-  int minor;
-  minor =  DEVICE_NR(inode->i_rdev);
-  
-#if AP_DEBUG
-  printk("ap_open: minor=%x\n", minor);
-#endif
-
-  if (minor >= NUM_APDEVS)
-    return -ENODEV;
-
-  /* if its already open then don't do anything */
-  if (ap_fds[minor] != -1)
-    return 0;
-
-  /* send the open request to the front end */
-  creq.cid = mpp_cid();
-  creq.type = REQ_BOPEN;
-  creq.header = 0;
-  creq.size = sizeof(creq);
-  creq.data[0] = minor;
-
-  bif_queue(&creq,0,0);
-
-  /* wait for the reply */
-  while (ap_fds[minor] == -1)
-    sleep_on(&busy_wait);
-
-  return 0;
-}
-
-
-static int ap_ioctl(struct inode *inode, struct file *file, 
-		    unsigned int cmd, unsigned long arg)
-{
-	if (!inode || !inode->i_rdev) 	
-		return -EINVAL;
-
-	switch (cmd) {
-	case BLKGETSIZE:   /* Return device size */
-		if (put_user(ap_length[MINOR(inode->i_rdev)],(long *) arg))
-			return -EFAULT;
-		return 0;
-    
-	default:
-		break;
-	};
-	
-	return 0;
-}
-
-
-/* this is called by ap1000/bif.c when a open reply comes in */
-void ap_open_reply(struct cap_request *creq)
-{
-  int minor = creq->data[0];
-
-  ap_fds[minor] = creq->data[1];
-  ap_length[minor] = creq->data[2] >> SECTOR_BLOCK_SHIFT;
-
-#if AP_DEBUG
-  printk("ap opened minor %d length=%d fd=%d\n",
-	 minor,ap_length[minor],ap_fds[minor]);
-#endif
-
-  wake_up(&busy_wait);  
-} 
-
-static struct block_device_operations ap_fops = {
-	open:		ap_open,
-	release:	ap_release,
-	ioctl:		ap_ioctl,
-};
-
-
-int ap_init(void)
-{
-  int i;
-  static int done = 0;
-
-  if (done) return(1);
-
-  if (register_blkdev(MAJOR_NR,"apblock",&ap_fops)) {
-    printk("ap: unable to get major %d for ap block dev\n",MAJOR_NR);
-    return -1;
-  }
-  printk("ap_init: register dev %d\n", MAJOR_NR);
-  blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &ap_request);
-
-  for (i=0;i<NUM_APDEVS;i++) {
-    ap_blocksizes[i] = AP_BLOCK_SIZE;
-    ap_length[i] = 0;
-    ap_fds[i] = -1;
-  }
-
-  blksize_size[MAJOR_NR] = ap_blocksizes;
-
-  read_ahead[MAJOR_NR] = 32; /* 16k read ahead */
-  for (i=0;i<NUM_APDEVS;i++)
-	register_disk(NILL, MKDEV(MAJOR_NR,i), 1, &ap_fops, 0);
-
-  return(0);
-}
-
-/* loadable module support */
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	int error = ap_init();
-	if (!error)
-		printk(KERN_INFO "APBLOCK: Loaded as module.\n");
-	return error;
-}
-
-/* Before freeing the module, invalidate all of the protected buffers! */
-void cleanup_module(void)
-{
-	int i;
-
-	for (i = 0 ; i < NUM_APDEVS; i++)
-		invalidate_buffers(MKDEV(MAJOR_NR, i));
-
-	unregister_blkdev( MAJOR_NR, "apblock" );
-	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-}
-
-#endif  /* MODULE */
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/apfddi-reg.h linux/drivers/ap1000/apfddi-reg.h
--- v2.3.41/linux/drivers/ap1000/apfddi-reg.h	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/apfddi-reg.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* FDDI register pointers */
-extern volatile struct formac *mac;
-extern volatile struct plc *plc;
-extern volatile int *csr0;
-extern volatile int *csr1;
-extern volatile int *buffer_mem;
-extern volatile int *fifo;
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/apfddi.c linux/drivers/ap1000/apfddi.c
--- v2.3.41/linux/drivers/ap1000/apfddi.c	Wed Aug 18 11:38:58 1999
+++ linux/drivers/ap1000/apfddi.c	Wed Dec 31 16:00:00 1969
@@ -1,702 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * $Id: apfddi.c,v 1.6 1996/12/18 01:45:51 tridge Exp $
- *
- * Network interface definitions for AP1000 fddi device.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/if_ether.h>	/* For the statistics structure. */
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-
-#include <linux/inet.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/irq.h>
-
-#include <net/arp.h>
-
-#include "apfddi.h"
-#include "smt-types.h"
-#include "mac.h"
-#include "plc.h"
-#include "am79c830.h"
-#include "apfddi-reg.h"
-
-volatile struct formac *mac;
-volatile struct plc *plc;
-volatile int *csr0;
-volatile int *csr1;
-volatile int *buffer_mem;
-volatile int *fifo;
-
-#define APFDDI_DEBUG 0
-
-#define APFDDI_IRQ    7
-
-#define T(x)	(-SECS_TO_FDDI_TIME(x))
-
-struct plc_info plc_info = {
-    pt_s,			/* port_type */
-    T(1.6e-3),			/* c_min */
-    T(50e-6),			/* tl_min */
-    T(5e-3),			/* tb_min */
-    T(100e-3),			/* t_out */
-    T(50e-3),			/* lc_short */
-    T(500e-3),			/* lc_medium */
-    T(5.0),			/* lc_long */
-    T(50.0),			/* lc_extended */
-    T(3.5e-3),			/* t_scrub */
-    T(1.3e-3),			/* ns_max */
-};
-
-struct mac_info mac_info = {
-    T(165e-3),			/* tmax */
-    T(3.5e-3),			/* tvx */
-    T(20e-3),			/* treq */
-    { 0x42, 0x59 },		/* s_address */
-    { 0x42, 0x59, 0x10, 0x76, 0x88, 0x82 },	/* l_address */
-    { 0 },			/* s_group_adrs */
-    { 0 },			/* l_group_adrs */
-    0,				/* rcv_own_frames */
-    1,				/* only_good_frames */
-};
-
-u_char fddi_bitrev[256] = {
-    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
-    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
-    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
-    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
-    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
-    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
-    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
-    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
-    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
-    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
-    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
-    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
-    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
-    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
-    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
-    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
-    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
-    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
-    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
-    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
-    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
-    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
-    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
-    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
-    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
-    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
-    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
-    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
-    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
-    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
-    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
-    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
-/* XXX our hardware address, canonical bit order */
-static u_char apfddi_saddr[6] = { 0x42, 0x9a, 0x08, 0x6e, 0x11, 0x41 };
-
-struct net_device *apfddi_device = NULL;
-struct net_device_stats *apfddi_stats = NULL;
-
-volatile struct apfddi_queue *apfddi_queue_top = NULL;
-
-void map_regs(void)
-{
-    unsigned long reg_base_addr = 0xfbf00000;
-
-    mac = (volatile struct formac *) (reg_base_addr + FORMAC);
-    plc = (volatile struct plc *) (reg_base_addr + PLC);
-    csr0 = (volatile int *) (reg_base_addr + CSR0);
-    csr1 = (volatile int *) (reg_base_addr + CSR1);
-    buffer_mem = (volatile int *) (reg_base_addr + BUFFER_MEM);
-    fifo = (volatile int *) (reg_base_addr + FIFO);
-}
-
-int ring_op;
-
-void apfddi_startup(void)
-{
-    int reason;
-
-#if APFDDI_DEBUG
-    printk("In apfddi_startup\n");
-#endif
-
-    *csr0 = CS0_LED0;
-    ring_op = 0;
-    if (*csr1 & 0xf078) {
-	*csr1 = CS1_RESET_MAC | CS1_RESET_FIFO;
-	*csr1 = 0;
-	reason = 1;
-	printk("resetting after power-on\n");
-    } else {
-	*csr1 = CS1_RESET_FIFO;
-	*csr1 = 0;
-	reason = plc_inited(&plc_info);
-	if (reason)
-	    printk("resetting: plc reason %d\n", reason);
-    }
-    if (reason) {
-#if APFDDI_DEBUG
-	printk("Calling plc_init\n");
-#endif
-	plc_init(&plc_info);
-#if APFDDI_DEBUG
-	printk("Calling mac_init\n");
-#endif
-	mac_init(&mac_info);
-	*csr0 |= CS0_LED1;
-	pc_start(loop_none);
-
-    } else {
-	*csr0 |= CS0_LED2 | CS0_LED1;
-	reason = mac_inited(&mac_info);
-	if (reason) {
-	    printk("resetting mac: reason %d\n", reason);
-	    mac_init(&mac_info);
-	    mac_reset(loop_none);
-	    mac_claim();
-	} else {
-	    ring_op = 1;
-	    *csr0 &= ~(CS0_LED0 | CS0_LED1 | CS0_LED2);
-	}
-    }
-}
-
-void apfddi_off(void)
-{
-    *csr0 &= ~CS0_LED1;
-    pc_stop();
-}
-
-void apfddi_sleep(void)
-{
-    mac_sleep();
-    plc_sleep();
-}
-
-void apfddi_poll(void)
-{
-    if (*csr0 & CS0_PHY_IRQ)
-	plc_poll();
-    if (*csr0 & CS0_MAC_IRQ)
-	mac_poll();
-}
-
-void set_cf_join(int on)
-{
-    if (on) {
-#if APFDDI_DEBUG
-	printk("apfddi: joined the ring!\n");
-#endif
-	mac_reset(loop_none);
-	*csr0 |= CS0_LED2;
-	mac_claim();
-    } else {
-	mac_disable();
-	ring_op = 0;
-	*csr0 = (*csr0 & ~CS0_LED2) | CS0_LED1 | CS0_LED0;
-    }
-}
-
-void set_ring_op(int up)
-{
-    ring_op = up;
-    if (up) {
-#if APFDDI_DEBUG
-	printk("apfddi: ring operational!\n");
-#endif
-	*csr0 &= ~(CS0_LED2 | CS0_LED1 | CS0_LED0);
-    } else
-	*csr0 |= CS0_LED2 | CS0_LED1 | CS0_LED0;
-}
-
-void rmt_event(int st)
-{
-    if (st & (S2_BEACON_STATE|S2_MULTIPLE_DA|S2_TOKEN_ERR
-	      |S2_DUPL_CLAIM|S2_TRT_EXP_RECOV)) {
-	printk("st2 = %x\n", st);
-    }
-}
-
-
-int apfddi_init(struct net_device *dev);
-static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int apfddi_xmit(struct sk_buff *skb, struct net_device *dev);
-int apfddi_rx(struct mac_buf *mbuf);
-static struct net_device_stats *apfddi_get_stats(struct net_device *dev);
-#if APFDDI_DEBUG
-void dump_packet(char *action, char *buf, int len, int seq);
-#endif
-
-/*
- * Create FDDI header for an arbitrary protocol layer
- *
- * saddr=NULL means use device source address (always will anyway)
- * daddr=NULL means leave destination address (eg unresolved arp)
- */
-static int apfddi_hard_header(struct sk_buff *skb, struct net_device *dev,
-			      unsigned short type, void *daddr,
-			      void *saddr, unsigned len)
-{
-    struct fddi_header *fh;
-    struct llc_header *lh;
-    u_char *base_header;
-    u_char *fd_daddr = (u_char *)daddr;
-    int i;
-
-#if APFDDI_DEBUG
-    printk("In apfddi_hard_header\n");
-#endif
-
-    if (skb == NULL) {
-	printk("Null skb in apfddi_hard_header... returning...\n");
-	return 0;
-    }
-
-    switch(type) {
-    case ETH_P_IP:
-#if APFDDI_DEBUG
-	printk("apfddi_hard_header: Processing IP packet\n");
-#endif
-	break;
-    case ETH_P_ARP:
-#if APFDDI_DEBUG
-	printk("apfddi_hard_header: Processing ARP packet\n");
-#endif
-	break;
-    case ETH_P_RARP:
-#if APFDDI_DEBUG
-	printk("apfddi_hard_header: Processing RARP packet\n");
-#endif
-	break;
-    default:
-	printk("apfddi_hard_header: I don't understand protocol %d (0x%x)\n",
-	       type, type);
-	apfddi_stats->tx_errors++;
-	return 0;
-    }
-
-    base_header = (u_char *)skb_push(skb, FDDI_HARDHDR_LEN-4);
-    if (base_header == NULL) {
-	printk("apfddi_hard_header: Memory squeeze, dropping packet.\n");
-	apfddi_stats->tx_dropped++;
-	return 0;
-    }
-    fh = (struct fddi_header *)(base_header + 3);
-    lh = (struct llc_header *)((char *)fh + FDDI_HDRLEN);
-
-    lh->llc_dsap = lh->llc_ssap = LLC_SNAP_LSAP;
-    lh->snap_control = LLC_UI;
-    lh->snap_org_code[0] = 0;
-    lh->snap_org_code[1] = 0;
-    lh->snap_org_code[2] = 0;
-    lh->snap_ether_type = htons(type);
-
-#if APFDDI_DEBUG
-    printk("snap_ether_type is %d (0x%x)\n", lh->snap_ether_type,
-	   lh->snap_ether_type);
-#endif
-    
-    fh->fddi_fc = FDDI_FC_LLC;
-    
-    /*
-     * Fill in the source address.
-     */
-    for (i = 0; i < 6; i++)
-	fh->fddi_shost[i] = fddi_bitrev[apfddi_saddr[i]];
-    
-    /*
-     * Fill in the destination address.
-     */
-    if (daddr) {
-#if APFDDI_DEBUG
-	printk("daddr is: ");
-#endif
-	for (i = 0; i < 6; i++) {
-	    fh->fddi_dhost[i] = fddi_bitrev[fd_daddr[i]];
-#if APFDDI_DEBUG
-	    printk("%x(%x):",fh->fddi_dhost[i], fd_daddr[i]);
-#endif
-	}
-#if APFDDI_DEBUG
-	printk("\n");
-#endif
-	return(FDDI_HARDHDR_LEN-4);
-    }
-    else {
-#if APFDDI_DEBUG
-	printk("apfddi_hard_header, daddr was NULL\n");
-#endif
-	return -(FDDI_HARDHDR_LEN-4);
-    }
-}
-
-/*
- * Rebuild the FDDI header. This is called after an ARP (or in future
- * other address resolution) has completed on this sk_buff. We now let
- * ARP fill in the other fields.  
- */
-static int apfddi_rebuild_header(void *buff, struct net_device *dev,
-				 unsigned long raddr, struct sk_buff *skb)
-{
-    int i, status;
-    struct fddi_header *fh = (struct fddi_header *)(buff+3);
-
-#if APFDDI_DEBUG
-    printk("In apfddi_rebuild_header, dev is %x apfddi_device is %x\n", dev,
-	   apfddi_device);
-    printk("rebuild header for fc 0x%x\n", fh->fddi_fc);
-    printk("dest address is:\n");
-    for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]);
-#endif
-    status = arp_find(raddr, skb) ? 1 : 0;
-    
-    if (!status) {
-#if APFDDI_DEBUG
-	printk("dest address is now:\n");
-	for (i = 0; i < 6; i++) printk("%x:", fh->fddi_dhost[i]);
-	printk("status is %d\n", status);
-#endif
-	/*
-	 * Bit reverse the dest_address.
-	 */
-	for (i = 0; i < 6; i++)
-	    fh->fddi_dhost[i] = fddi_bitrev[fh->fddi_dhost[i]];
-    }
-#if APFDDI_DEBUG    
-    printk("\n");
-#endif
-    return(status);
-}
-
-static int apfddi_set_mac_address(struct net_device *dev, void *addr)
-{
-#if APFDDI_DEBUG
-    printk("In apfddi_set_mac_address\n");
-#endif
-    return (0);
-}
-
-static void apfddi_set_multicast_list(struct net_device *dev)
-{
-#if APFDDI_DEBUG
-    printk("In apfddi_set_multicast_list\n");
-#endif
-}
-
-static int apfddi_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-#if APFDDI_DEBUG
-    printk("In apfddi_do_ioctl\n");
-#endif
-    return (0);
-}
-
-static int apfddi_set_config(struct net_device *dev, struct ifmap *map)
-{
-#if APFDDI_DEBUG
-    printk("In apfddi_set_config\n");
-#endif
-    return (0);
-}
-
-/*
- * Opening the fddi device through ifconfig.
- */
-int apfddi_open(struct net_device *dev)
-{
-    static int already_run = 0;
-    unsigned flags;
-    int res;
-
-    if (already_run) {
-	apfddi_startup();
-	*csr0 |= CS0_INT_ENABLE;
-	return 0;
-    }
-    already_run = 1;
-
-    map_regs();
-    apfddi_startup();
-
-    save_flags(flags); cli();
-    if ((res = request_irq(APFDDI_IRQ, apfddi_interrupt, SA_INTERRUPT, 
-			   "apfddi", dev))) {
-	printk("Failed to install apfddi handler error=%d\n", res);
-	restore_flags(flags);
-	return(0);
-    }
-    enable_irq(APFDDI_IRQ);
-    restore_flags(flags);
-
-#if APFDDI_DEBUG
-    printk("Installed apfddi interrupt handler\n");
-#endif
-    *csr0 |= CS0_INT_ENABLE;
-#if APFDDI_DEBUG
-    printk("Enabled fddi interrupts\n");
-#endif
-    
-    return 0;
-}
-
-/*
- * Stop the fddi device through ifconfig.
- */
-int apfddi_stop(struct net_device *dev)
-{
-    *csr0 &= ~CS0_INT_ENABLE;
-    apfddi_sleep();
-    return 0;
-}
-
-
-/*
- * Initialise fddi network interface.
- */
-int apfddi_init(struct net_device *dev)
-{
-    int i;
-
-    /*
-     * Check if this thing has already been initialised.
-     */
-    if (apfddi_device != NULL)
-	return -ENODEV;
-
-    printk("apfddi_init(): Initialising fddi interface\n");
-
-    apfddi_device = dev;
-
-    dev->open = apfddi_open;
-    dev->stop = apfddi_stop;
-    dev->hard_start_xmit = apfddi_xmit;
-    dev->get_stats = apfddi_get_stats;
-    dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_ATOMIC); 
-    if (dev->priv == NULL)
-	return -ENOMEM;
-    memset(dev->priv, 0, sizeof(struct net_device_stats)); 
-    apfddi_stats = (struct net_device_stats *)apfddi_device->priv;
-
-    /* Initialise the fddi device structure */
-    for (i = 0; i < DEV_NUMBUFFS; i++)
-	skb_queue_head_init(&dev->buffs[i]);
-    
-    dev->hard_header = apfddi_hard_header;
-    dev->rebuild_header	= apfddi_rebuild_header;
-    dev->set_mac_address = apfddi_set_mac_address;
-    dev->header_cache_update = NULL;
-    dev->do_ioctl = apfddi_do_ioctl;    
-    dev->set_config = apfddi_set_config;
-    dev->set_multicast_list = apfddi_set_multicast_list;
-    dev->type = ARPHRD_ETHER;
-    dev->hard_header_len = FDDI_HARDHDR_LEN;
-    dev->mtu = FDDIMTU;
-    dev->addr_len = 6;
-    memcpy(dev->dev_addr, apfddi_saddr, sizeof(apfddi_saddr));
-    dev->tx_queue_len = 100;    /* XXX What should this be? */
-    dev->irq = APFDDI_IRQ;
-
-    memset(dev->broadcast, 0xFF, ETH_ALEN);
-    
-    return(0);
-}
-
-static void apfddi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-#if APFDDI_DEBUG
-    static int times = 0;
-#endif
-    unsigned flags;
-    save_flags(flags); cli();
-    
-#if APFDDI_DEBUG
-    printk("In apfddi_interrupt irq %d dev_id %p times %d\n",
-	   irq, dev_id, ++times);
-#endif
-    
-    apfddi_poll();
-    restore_flags(flags);
-}
-
-#if APFDDI_DEBUG
-static char *flagbits[8] = {
-    "fin", "syn", "rst", "push", "ack", "urg", "6", "7"
-};
-
-void dump_packet(action, buf, len, seq)
-    char *action, *buf;
-    int len, seq;
-{
-    int i, flags;
-    char *sep;
-
-    printk("%s packet %d of %d bytes at %d:\n", action, seq,
-	   len, jiffies);
-    printk("  from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n",
-	   *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4),
-	   *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2));
-    if( buf[9] == 6 || buf[9] == 17 ){
-	/* TCP or UDP */
-	printk("  sport=%d dport=%d",
-	       *(u_short *)(buf+20), *(u_short *)(buf+22));
-	if( buf[9] == 6 ){
-	    printk(" seq=%d ack=%d win=%d flags=<",
-		   *(long *)(buf+24), *(long *)(buf+28),
-		   *(unsigned short *)(buf+34));
-	    flags = buf[33];
-	    sep = "";
-	    for (i = 7; i >= 0; --i) {
-		if (flags & (1 << i)) {
-		    printk("%s%s", sep, flagbits[i]);
-		    sep = "+";
-		}
-	    }
-	    printk(">");
-	}
-	printk("\n");
-    }
-}
-#endif
-
-#if APFDDI_DEBUG
-static void apfddi_print_frame(struct sk_buff *skb)
-{
-    int i;
-    struct llc_header *lh;
-    static int seq = 0;
-
-#if 0
-    printk("skb->len is %d\n", skb->len);
-    printk("fc is 0x%x\n", *(u_char *)(skb->data+3));
-    printk("dest address is:\n");
-    for (i = 0; i < 6; i++) {
-	printk("%x:", fddi_bitrev[*(u_char *)(skb->data+4+i)]);
-    }
-    printk("\n");
-    printk("source address is:\n");
-    for (i = 0; i < 6; i++) {
-	printk("%x:", fddi_bitrev[*(u_char *)(skb->data+10+i)]);
-    }
-    printk("\n");
-#endif
-    lh = (struct llc_header *)(skb->data+16);
-#if 0
-    printk("llc_dsp %d llc_ssap %d snap_control %d org_code [0]=%d [1]=%d [2]=%d ether_type=%d\n",
-	   lh->llc_dsap, lh->llc_ssap, lh->snap_control,
-	   lh->snap_org_code[0], lh->snap_org_code[1], lh->snap_org_code[2],
-	   lh->snap_ether_type);
-#endif
-    if (lh->snap_ether_type == ETH_P_IP)
-	dump_packet("apfddi_xmit:", skb->data+24, skb->len-24, seq++);
-}
-#endif
-
-/*
- * Transmitting packet over FDDI.
- */
-static int apfddi_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-    unsigned long flags;
-    
-#if APFDDI_DEBUG
-    printk("In apfddi_xmit\n");
-#endif
-
-    /*
-     * Check there is some work to do.
-     */
-    if (skb == NULL || dev == NULL) 
-	return(0);
-
-#if APFDDI_DEBUG
-    printk("skb address is for apfddi 0x%x\n", skb);
-#endif
-
-    /*
-     * Check lock variable.
-     */
-    save_flags(flags); cli();
-    if (dev->tbusy != 0) {
-	restore_flags(flags);
-	printk("apfddi_xmit: device busy\n");
-	apfddi_stats->tx_errors++;
-	return 1;
-    }
-    restore_flags(flags);
-    dev->tbusy = 1;
-
-    dev->trans_start = jiffies;
-
-    skb->mac.raw = skb->data;
-
-    /*
-     * Append packet onto send queue.
-     */
-    if (mac_queue_append(skb)) {
-	/*
-	 * No memory.
-	 */
-	return 1;
-    }
-
-    /*
-     * Process packet queue.
-     */
-    mac_process();
-
-    apfddi_stats->tx_packets++;
-    dev->tbusy = 0;
-    return 0;
-}
-
-#if APFDDI_DEBUG
-void print_mbuf(struct mac_buf *mbuf)
-{
-    printk("mac %p length=%d ptr=%p wraplen=%d wrapptr=%x fr_start=%d fr_end=%d\n",
-	   mbuf, mbuf->length, mbuf->ptr, mbuf->wraplen, mbuf->wrapptr,
-	   mbuf->fr_start, mbuf->fr_end);
-}
-#endif
-
-/*
- * Return statistics of fddi driver.
- */
-static struct net_device_stats *apfddi_get_stats(struct net_device *dev)
-{
-    return((struct net_device_stats *)dev->priv);
-}
-
-    
-
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/apfddi.h linux/drivers/ap1000/apfddi.h
--- v2.3.41/linux/drivers/ap1000/apfddi.h	Wed Aug 18 11:38:58 1999
+++ linux/drivers/ap1000/apfddi.h	Wed Dec 31 16:00:00 1969
@@ -1,142 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-#define BUFFER_MEM	0x40000
-#define CSR0		0x60000
-#define CSR1		0x60004
-#define PLC		0x60080
-#define FORMAC		0x60200
-#define FIFO		0x68000
-
-/* Size of buffer memory */
-#define BUFFER_SIZE	32768		/* words; 128kB */
-
-/* Bits in CSR0 */
-#define CS0_INT_REQ	0x8000		/* board interrupt request asserted */
-#define CS0_MAC_IRQ	0x4000		/* FORMAC is requesting interrupt */
-#define CS0_PHY_IRQ	0x2000		/* PLC is requesting interrupt */
-#define CS0_LED2	0x1000		/* turn on led 2 */
-#define CS0_DO_IRQ	0x0200		/* request interrupt */
-#define CS0_INT_ENABLE	0x0100		/* enable interrupt requests */
-#define CS0_DMA_ENABLE	0x0080		/* enable DMA requests */
-#define CS0_DMA_RECV	0x0040		/* DMA requests are in receive dirn. */
-#define CS0_LED1	0x0010		/* turn on led 1 */
-#define CS0_LED0	0x0008		/* turn on led 0 (red) */
-#define CS0_HREQ	0x0007		/* host request to FORMAC */
-#define CS0_HREQ_WSPEC	0x0002		/* write special frames */
-#define CS0_HREQ_RECV	0x0003		/* read receive queue */
-#define CS0_HREQ_WS	0x0004		/* write synchronous queue */
-#define CS0_HREQ_WA0	0x0005		/* write async queue 0 */
-#define CS0_HREQ_WA1	0x0006		/* write async queue 1 */
-#define CS0_HREQ_WA2	0x0007		/* write async queue 2 */
-
-/* Bits in CSR1 */
-#define CS1_THIS_QAF	0x0800		/* this queue almost full */
-#define CS1_FIFO_TAG	0x0400		/* tag of word at head of fifo */
-#define CS1_BUF_RD_TAG	0x0200		/* tag of last word read from buffer */
-#define CS1_BUF_WR_TAG	0x0100		/* tag to write to buffer */
-#define CS1_TAGMODE	0x0080		/* enable tag mode */
-#define CS1_RESET_MAC	0x0040		/* reset FORMAC and PLC */
-#define CS1_RESET_FIFO	0x0020		/* reset FIFO */
-#define CS1_CLEAR_QAF	0x0010		/* clear queue-almost-full bits */
-#define CS1_FIFO_LEVEL	0x0007		/* # words in FIFO (0 - 4) */
-
-/*
- * FDDI Frame Control values.
- */
-#define FDDI_SMT		0x41
-#define FDDI_SMT_NSA		0x4f
-#define FDDI_FC_LLC		0x50
-#define FDDI_FC_LLC_MASK	0xf0
-
-/*
- * Unnumbered LLC format commands
- */
-#define LLC_UI		0x3
-#define LLC_UI_P	0x13
-#define LLC_DISC	0x43
-#define	LLC_DISC_P	0x53
-#define LLC_UA		0x63
-#define LLC_UA_P	0x73
-#define LLC_TEST	0xe3
-#define LLC_TEST_P	0xf3
-#define LLC_FRMR	0x87
-#define	LLC_FRMR_P	0x97
-#define LLC_DM		0x0f
-#define	LLC_DM_P	0x1f
-#define LLC_XID		0xaf
-#define LLC_XID_P	0xbf
-#define LLC_SABME	0x6f
-#define LLC_SABME_P	0x7f
-
-/*
- * Supervisory LLC commands
- */
-#define	LLC_RR		0x01
-#define	LLC_RNR		0x05
-#define	LLC_REJ		0x09
-
-/*
- * Info format - dummy only
- */
-#define	LLC_INFO	0x00
-
-/*
- * ISO PDTR 10178 contains among others
- */
-#define LLC_X25_LSAP	0x7e
-#define LLC_SNAP_LSAP	0xaa
-#define LLC_ISO_LSAP	0xfe
-
-/*
- * Structure of the FDDI MAC header.
- */
-struct fddi_header {
-    u_char	fddi_fc;	/* frame control field */
-    u_char	fddi_dhost[6];	/* destination address */
-    u_char	fddi_shost[6];	/* source address */
-};
-
-/*
- * Structure of LLC/SNAP header.
- */
-struct llc_header {
-  u_char llc_dsap;
-  u_char llc_ssap;
-  u_char snap_control;
-  u_char snap_org_code[3];
-  u_short snap_ether_type;
-};
-  
-#define FDDI_HDRLEN	13	/* sizeof(struct fddi_header) */
-#define LLC_SNAPLEN	8	/* bytes for LLC/SNAP header */
-#define FDDI_HARDHDR_LEN 28     /* Hard header size */
-
-#define FDDIMTU		4352
-
-
-/* Types of loopback we can do. */
-typedef enum {
-    loop_none,
-    loop_formac,
-    loop_plc_lm,
-    loop_plc_eb,
-    loop_pdx
-} LoopbackType;
-
-/* Offset from fifo for writing word with tag. */
-#define FIFO_TAG	0x80
-
-#define MAX_FRAME_LEN	4500
-
-void set_ring_op(int up);
-void rmt_event(int st);
-void set_cf_join(int on);
-
-extern struct net_device *apfddi_device;
-extern struct net_device_stats *apfddi_stats;
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/bif.c linux/drivers/ap1000/bif.c
--- v2.3.41/linux/drivers/ap1000/bif.c	Wed Aug 18 11:38:58 1999
+++ linux/drivers/ap1000/bif.c	Wed Dec 31 16:00:00 1969
@@ -1,280 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * $Id: bif.c,v 1.13 1996/12/18 01:45:52 tridge Exp $
- *
- * Network interface definitions for bif device.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/if_ether.h>	/* For the statistics structure. */
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>	/* For ARPHRD_BIF */
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-
-#include <linux/inet.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apreg.h>
-
-#define BIF_DEBUG 0
-#if BIF_DEBUG
-static int seq = 0;
-#endif
-
-#define BIF_MTU 10240
-
-static struct net_device *bif_device = 0;
-static struct net_device_stats *bif_stats = 0;
-
-int bif_init(struct net_device *dev);
-int bif_open(struct net_device *dev);
-static int bif_xmit(struct sk_buff *skb, struct net_device *dev);
-int bif_rx(struct sk_buff *skb);
-int bif_stop(struct net_device *dev);
-static struct net_device_stats *bif_get_stats(struct net_device *dev);
-
-static int bif_hard_header(struct sk_buff *skb, struct net_device *dev,
-			   unsigned short type, void *daddr,
-			   void *saddr, unsigned len)
-{
-#if BIF_DEBUG
-  printk("bif_hard_header()\n");
-#endif
-  
-  skb_push(skb,dev->hard_header_len);
-
-  if (daddr) skb->arp = 1;
-
-  /* tell IP how much space we took */
-  return (dev->hard_header_len);
-}
-
-static int bif_rebuild_header(void *buff, struct net_device *dev,
-			      unsigned long raddr, struct sk_buff *skb)
-{
-  /* this would normally be used to fill in hardware addresses after
-     an ARP */
-#if BIF_DEBUG
-  printk("bif_rebuild_header()\n");
-#endif
-  if (skb) skb->arp = 1;
-  return(0);
-}
-
-static int bif_set_mac_address(struct net_device *dev, void *addr)
-{
-  printk("BIF: set_mac_address called\n");
-  return (0);
-}
-
-static void bif_set_multicast_list(struct net_device *dev)
-{
-  return;
-}
-
-static int bif_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-  printk("BIF: Called do_ioctl\n");
-  return (0);
-}
-
-static int bif_set_config(struct net_device *dev, struct ifmap *map)
-{
-  printk("BIF: Called bif_set_config\n");
-  return (0);
-}
-
-/*
- * Initialise bif network interface.
- */
-int bif_init(struct net_device *dev)
-{
-    int i;
-
-    printk("bif_init(): Initialising bif interface\n");
-    bif_device = dev;
-
-    dev->mtu = BIF_MTU;
-    dev->tbusy = 0;
-    dev->hard_start_xmit = bif_xmit;
-    dev->hard_header = bif_hard_header;
-    dev->hard_header_len = sizeof(struct cap_request);
-    dev->addr_len = 0;
-    dev->tx_queue_len = 50000;    /* no limit (almost!) */
-    dev->type = ARPHRD_BIF;
-    dev->rebuild_header	= bif_rebuild_header;
-    dev->open = bif_open;
-    dev->flags = IFF_NOARP;   /* Don't use ARP on this device */
-    dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
-    if (dev->priv == NULL)
-	return -ENOMEM;
-    memset(dev->priv, 0, sizeof(struct net_device_stats));
-    bif_stats = (struct net_device_stats *)bif_device->priv;
-
-
-    dev->stop = bif_stop;
-    dev->get_stats = bif_get_stats;
-
-    dev->set_mac_address = bif_set_mac_address;
-    dev->header_cache_update = NULL;
-    dev->do_ioctl = bif_do_ioctl;    
-    dev->set_config = bif_set_config;
-    dev->set_multicast_list = bif_set_multicast_list;
-
-    memset(dev->broadcast, 0xFF, ETH_ALEN);
-
-    dev_init_buffers(dev);
-    
-    return(0);
-}
-
-int bif_open(struct net_device *dev)
-{
-    printk("In bif_open\n");
-    dev->tbusy = 0;
-    dev->start = 1;
-    return 0;
-}
-
-#if BIF_DEBUG
-static void dump_packet(char *action, char *buf, int len, int seq)
-{
-    int flags;
-    char *sep;
-
-    printk("%s packet %d of %d bytes at %d:\n", action, seq,
-	   len, (int)jiffies);
-    printk("  from %x to %x pktid=%d ttl=%d pcol=%d len=%d\n",
-	   *(long *)(buf+12), *(long *)(buf+16), *(u_short *)(buf+4),
-	   *(unsigned char *)(buf+8), buf[9], *(u_short *)(buf+2));
-    if( buf[9] == 6 || buf[9] == 17 ){
-	/* TCP or UDP */
-	printk("  sport=%d dport=%d",
-	       *(u_short *)(buf+20), *(u_short *)(buf+22));
-	if( buf[9] == 6 ){
-	    printk(" seq=%d ack=%d win=%d flags=<",
-		   *(long *)(buf+24), *(long *)(buf+28),
-		   *(unsigned short *)(buf+34));
-	    flags = buf[33];
-	    sep = "";
-	    printk(">");
-	}
-	printk("\n");
-    }
-    else {
-	printk("  protocol = %d\n", buf[9]);
-    }
-}
-#endif
-
-
-static int bif_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	extern int bif_send_ip(int cid,struct sk_buff *skb);
-	extern int tnet_send_ip(int cid,struct sk_buff *skb);
-	extern int msc_blocked, tnet_ip_enabled;
-	u_long destip;
-	int cid;
-
-	if (skb == NULL || dev == NULL) 
-		return(0);
-  
-	destip = *(u_long *)(skb->data+sizeof(struct cap_request)+16);
-	cid = ap_ip_to_cid(destip);
-
-	skb->dev = dev;
-	skb->mac.raw = skb->data;
-
-	if (cid != -1 && tnet_ip_enabled && !msc_blocked) {
-		tnet_send_ip(cid,skb);
-	} else {
-		bif_send_ip(cid, skb);
-	}
-  
-	dev->tbusy = 0;
-  
-	bif_stats->tx_packets++;
-
-	mark_bh(NET_BH);
-  
-	return 0;
-}
-
-
-/*
- * Receive a packet from the BIF - called from interrupt handler.
- */
-int bif_rx(struct sk_buff *skb)
-{
-#if BIF_DEBUG
-	dump_packet("bif_rx:", skb->data, skb->len, seq++);
-#endif
-
-	if (bif_device == NULL) {
-		printk("bif: bif_device is NULL in bif_rx\n");
-		dev_kfree_skb(skb);
-		return 0;
-	}
-	skb->dev = bif_device;
-	skb->protocol = ETH_P_IP;
-	
-#if 1
-	/* try disabling checksums on receive */
-	if (ap_ip_to_cid(*(u_long *)(((char *)skb->data)+12)) != -1)
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-#endif
-	
-	/*
-	 * Inform the network layer of the new packet.
-	 */
-	skb->mac.raw = skb->data;
-	netif_rx(skb);
-	
-	if (bif_stats == NULL) {
-		printk("bif: bif_stats is NULL is bif_rx\n");
-		return 0;
-	}
-	bif_stats->rx_packets++;
-	
-	return 0;
-}
-
-int bif_stop(struct net_device *dev)
-{
-	printk("in bif_close\n");
-
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	return 0;
-}
-
-/*
- * Return statistics of bif driver.
- */
-static struct net_device_stats *bif_get_stats(struct net_device *dev)
-{
-    return((struct net_device_stats *)dev->priv);
-}
-    
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/ddv.c linux/drivers/ap1000/ddv.c
--- v2.3.41/linux/drivers/ap1000/ddv.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ap1000/ddv.c	Wed Dec 31 16:00:00 1969
@@ -1,1008 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* 
- * ddv.c - Single AP1000 block driver.
- *
- * This block driver performs io operations to the ddv option
- * board. (Hopefully:)
- *
- */
-
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
-#include <linux/sched.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <linux/module.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/DdvReqTable.h>
-
-#define MAJOR_NR DDV_MAJOR
-
-#include <linux/blk.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h> 
-
-#define DDV_DEBUG 0
-#define AIR_DISK 1
-
-#define SECTOR_SIZE 512
-
-/* we can have lots of partitions */
-#define PARTN_BITS 6
-#define NUM_DDVDEVS (1<<PARTN_BITS)
-
-#define PARDISK_BASE (1<<5) /* partitions above this number are 
-			       striped	across all the cells */
-#define STRIPE_SHIFT   6
-#define STRIPE_SECTORS (1<<STRIPE_SHIFT) /* number of sectors per stripe */
-
-#define MAX_BNUM 16
-#define MAX_REQUEST (TABLE_SIZE - 2)
-#define REQUEST_LOW 16
-#define REQUEST_HIGH 4
-
-
-/* we fake up a block size larger than the physical block size to try
-   to make things a bit more efficient */
-#define SECTOR_BLOCK_SHIFT 9
-
-#define SECTOR_MASK ((BLOCK_SIZE >> 9) - 1)
-
-/* try to read ahead a bit */
-#define DDV_READ_AHEAD 64
-
-static int have_ddv_board = 1;
-static unsigned num_options = 0;
-static unsigned this_option = 0;
-
-extern int ddv_get_mlist(unsigned mptr[],int bnum);
-extern int ddv_set_request(struct request *req,
-			   int request_type,int bnum,int mlist,int len,int offset);
-extern void ddv_load_kernel(char *opcodep);
-extern int ddv_restart_cpu(void);
-extern int ddv_mlist_available(void);
-static int ddv_revalidate(kdev_t dev, struct gendisk *gdev);
-static void ddv_geninit(void);
-static void ddv_release(struct inode * inode, struct file * filp);
-static void ddv_request1(void);
-
-
-static char *ddv_opcodep = NULL;
-static struct request *next_request = NULL;
-
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-static int ddv_blocksizes[NUM_DDVDEVS]; /* in bytes */
-int ddv_sect_length[NUM_DDVDEVS]; /* in sectors */
-int ddv_blk_length[NUM_DDVDEVS]; /* in blocks */
-
-/* these are used by the ddv_daemon, which services remote disk requests */
-static struct remote_request *rem_queue = NULL;
-static struct remote_request *rem_queue_end;
-static DECLARE_WAIT_QUEUE_HEAD(ddv_daemon_wait);
-
-static int opiu_kernel_loaded = 0;
-
-static struct {
-	unsigned reads, writes, blocks, rq_started, rq_finished, errors;
-	unsigned sectors_read, sectors_written;
-} ddv_stats;
-
-static struct hd_struct partition_tables[NUM_DDVDEVS];
-
-static struct gendisk ddv_gendisk = {
-	MAJOR_NR,	/* Major number */
-	DEVICE_NAME,		/* Major name */
-	PARTN_BITS,		/* Bits to shift to get real from partition */
-	1 << PARTN_BITS,	/* Number of partitions per real */
-	partition_tables,/* hd struct */
-	ddv_blk_length,	/* block sizes */
-	1,		/* number */
-	(void *) NULL,	/* internal */
-	NULL		/* next */
-};
-
-struct ddv_geometry {
-	unsigned char heads;
-	unsigned char sectors;
-	unsigned short cylinders;
-	unsigned long start;
-}; 
-
-static struct ddv_geometry ddv_geometry;
-
-
-struct remote_request {
-	union {
-		struct remote_request *next;
-		void (*fn)(void);
-	} u;
-	unsigned bnum; /* how many blocks does this contain */
-	struct request *reqp; /* pointer to the request on the original cell */
-	unsigned cell; /* what cell is the request from */
-	struct request req; /* details of the request */
-};
-
-
-static void ddv_set_optadr(void)
-{
-	unsigned addr = 0x11000000;
-	OPT_IO(OBASE) = addr;
-	MSC_IO(MSC_OPTADR) = 
-		((addr & 0xff000000)>>16) |
-			((OPTION_BASE & 0xf0000000)>>24) | 
-				((OPTION_BASE + 0x10000000)>>28); 
-	OPT_IO(PRST) = 0;
-}
-
-extern struct RequestTable *RTable;
-extern struct OPrintBufArray *PrintBufs;
-extern struct OAlignBufArray *AlignBufs;
-extern struct DiskInfo *DiskInfo;
-
-static void ddv_release(struct inode * inode, struct file * filp)
-{
-#if DEBUG
-	printk("ddv_release started\n");
-#endif
-#if DEBUG
-	printk("ddv_release done\n");
-#endif
-}
-
-
-static unsigned in_request = 0;
-static unsigned req_queued = 0;
-
-static void ddv_end_request(int uptodate,struct request *req) 
-{
-	struct buffer_head * bh;
-
-	ddv_stats.rq_finished++;
-
-/*	printk("ddv_end_request(%d,%p)\n",uptodate,req); */
-
-	req->errors = 0;
-	if (!uptodate) {
-		printk("end_request: I/O error, dev %s, sector %lu\n",
-		       kdevname(req->rq_dev), req->sector);
-		req->nr_sectors--;
-		req->nr_sectors &= ~SECTOR_MASK;
-		req->sector += (BLOCK_SIZE / SECTOR_SIZE);
-		req->sector &= ~SECTOR_MASK;		
-		ddv_stats.errors++;
-	}
-	
-	if ((bh = req->bh) != NULL) {
-		req->bh = bh->b_reqnext;
-		bh->b_reqnext = NULL;
-		mark_buffer_uptodate(bh, uptodate);
-		unlock_buffer(bh);
-		if ((bh = req->bh) != NULL) {
-			req->current_nr_sectors = bh->b_size >> 9;
-			if (req->nr_sectors < req->current_nr_sectors) {
-				req->nr_sectors = req->current_nr_sectors;
-				printk("end_request: buffer-list destroyed\n");
-			}
-			req->buffer = bh->b_data;
-			printk("WARNING: ddv: more sectors!\n");
-			ddv_stats.errors++;
-			return;
-		}
-	}
-	if (req->sem != NULL)
-		up(req->sem);
-	req->rq_status = RQ_INACTIVE;	
-	wake_up(&wait_for_request);
-}
-
-
-/* check that a request is all OK to process */
-static int request_ok(struct request *req)
-{
-	int minor;
-	if (!req) return 0;
-
-	if (MAJOR(req->rq_dev) != MAJOR_NR)
-		panic(DEVICE_NAME ": bad major number\n");
-	if (!buffer_locked(req->bh))
-		panic(DEVICE_NAME ": block not locked");
-	
-	minor = MINOR(req->rq_dev);
-	if (minor >= NUM_DDVDEVS) {
-		printk("ddv_request: Invalid minor (%d)\n", minor);
-		return 0;
-	}
-
-	if ((req->sector + req->current_nr_sectors) > ddv_sect_length[minor]) {
-		printk("ddv: out of range minor=%d offset=%d len=%d sect_length=%d\n",
-		       minor,(int)req->sector,(int)req->current_nr_sectors,
-		       ddv_sect_length[minor]);
-		return 0;
-	}
-
-	if (req->cmd != READ && req->cmd != WRITE) {
-		printk("unknown request type %d\n",req->cmd);
-		return 0;
-	}			
-
-	/* it seems to be OK */
-	return 1;
-}
-
-
-static void complete_request(struct request *req,int bnum)
-{
-	while (bnum--) {
-		ddv_end_request(1,req);
-		req = req->next;
-	}
-}
-
-
-static int completion_pointer = 0;
-
-static void check_completion(void)
-{
-	int i,bnum;
-	struct request *req;
-
-	if (!RTable) return;
-
-	for (;
-	     (i=completion_pointer) != RTable->ddv_pointer &&
-	     RTable->async_info[i].status == DDV_REQ_FREE;
-	     completion_pointer = INC_T(completion_pointer))	     
-	{
-		req = (struct request *)RTable->async_info[i].argv[7];
-		bnum = RTable->async_info[i].bnum;
-		if (!req || !bnum) {
-			printk("%s(%d)\n",__FILE__,__LINE__);
-			ddv_stats.errors++;
-			continue;
-		}
-			
-		RTable->async_info[i].status = 0;
-		RTable->async_info[i].argv[7] = 0;
-
-		complete_request(req,bnum);
-		in_request--;		
-	}
-}
-
-
-static struct request *get_request_queue(struct request *oldq)
-{
-	struct request *req,*req2;
-
-	/* skip any non-active or bad requests */
- skip1:
-	if (!(req = CURRENT)) 
-		return oldq;
-
-	if (req->rq_status != RQ_ACTIVE) {
-		CURRENT = req->next;
-		goto skip1;
-	}
-
-	if (!request_ok(req)) {
-		ddv_end_request(0,req);
-		CURRENT = req->next;
-		goto skip1;
-	}
-
-	/* now grab as many as we can */
-	req_queued++;
-
-	for (req2 = req;
-	     req2->next && 
-	     req2->next->rq_status == RQ_ACTIVE &&
-	     request_ok(req2->next);
-	     req2 = req2->next) 
-		req_queued++;
-
-	/* leave CURRENT pointing at the bad ones */
-	CURRENT = req2->next;
-
-	/* chop our list at that point */
-	req2->next = NULL;
-
-	if (!oldq)
-		return req;
-
-	for (req2=oldq;req2->next;req2=req2->next) ;
-
-	req2->next = req;
-
-	return oldq;	
-}
-
-
-static void ddv_rem_complete(struct remote_request *rem)
-{
-	unsigned flags;
-	int bnum = rem->bnum;
-	struct request *req = rem->reqp;
-
-	complete_request(req,bnum);
-	in_request--;
-
-	save_flags(flags); cli();
-	ddv_request1();
-	restore_flags(flags);
-}
-
-
-/*
- * The background ddv daemon. This receives remote disk requests
- * and processes them via the normal block operations
- */
-static int ddv_daemon(void *unused)
-{
-	current->session = 1;
-	current->pgrp = 1;
-	sprintf(current->comm, "ddv_daemon");
-	spin_lock_irq(&current->sigmask_lock);
-	sigfillset(&current->blocked); /* block all signals */
-	recalc_sigpending(current);
-	spin_unlock_irq(&current->sigmask_lock);
-  
-	/* Give it a realtime priority. */
-	current->policy = SCHED_FIFO;
-	current->priority = 32;  /* Fixme --- we need to standardise our
-				    namings for POSIX.4 realtime scheduling
-				    priorities.  */
-  
-	printk("Started ddv_daemon\n");
-  
-	while (1) {
-		struct remote_request *rem;
-		unsigned flags;
-		struct buffer_head *bhlist[MAX_BNUM*4];
-		int i,j,minor,len,shift,offset;
-
-		save_flags(flags); cli();
-
-		while (!rem_queue) {
-			spin_lock(&current->sigmask_lock);
-			flush_signals(current);
-			spin_unlock(&current->sigmask_lock);
-			interruptible_sleep_on(&ddv_daemon_wait);
-			__sti(); cli();
-		}
-
-		rem = rem_queue;
-		rem_queue = rem->u.next;
-		restore_flags(flags);
-			
-
-		minor = MINOR(rem->req.rq_dev);
-		len = rem->req.current_nr_sectors;
-		offset = rem->req.sector;
-
-		/* work out the conversion to the local block size from
-		   sectors */
-		for (shift=0;
-		     (SECTOR_SIZE<<shift) != ddv_blocksizes[minor];
-		     shift++) ;
-
-		/* do the request */
-		for (i=0; len; i++) {
-			bhlist[i] = getblk(rem->req.rq_dev, 
-					   offset >> shift,
-					   ddv_blocksizes[minor]);
-			if (!buffer_uptodate(bhlist[i]))
-				ll_rw_block(READ,1,&bhlist[i]);
-			offset += 1<<shift;
-			len -= 1<<shift;
-		}
-			    
-		for (j=0;j<i;j++)
-			if (!buffer_uptodate(bhlist[j]))
-				wait_on_buffer(bhlist[j]);
-		
-		
-		/* put() the data */
-		
-
-		/* release the buffers */
-		for (j=0;j<i;j++)
-			brelse(bhlist[j]);
-
-		/* tell the originator that its done */
-		rem->u.fn = ddv_rem_complete;
-		tnet_rpc(rem->cell,rem,sizeof(int)*3,1);
-	}
-}
-
-
-/* receive a remote disk request */
-static void ddv_rem_queue(char *data,unsigned size)
-{
-	unsigned flags;
-	struct remote_request *rem = (struct remote_request *)
-		kmalloc(size,GFP_ATOMIC);
-
-	if (!rem) {
-		/* oh bugger! */
-		ddv_stats.errors++;
-		return;
-	}
-
-	memcpy(rem,data,size);
-	rem->u.next = NULL;
-
-	save_flags(flags); cli();
-
-	/* add it to our remote request queue */
-	if (!rem_queue)
-		rem_queue = rem;
-	else
-		rem_queue_end->u.next = rem;
-	rem_queue_end = rem;
-
-	restore_flags(flags);
-
-	wake_up(&ddv_daemon_wait);  
-}
-
-
-/* which disk should this request go to */
-static inline unsigned pardisk_num(struct request *req)
-{
-	int minor = MINOR(req->rq_dev);
-	unsigned stripe;
-	unsigned cell;
-
-	if (minor < PARDISK_BASE)
-		return this_option;
-
-	stripe = req->sector >> STRIPE_SHIFT;
-	cell = stripe % num_options;
-
-	return cell;
-}
-
-
-/* check if a 2nd request can be tacked onto the first */
-static inline int contiguous(struct request *req1,struct request *req2)
-{
-	if (req2->cmd != req1->cmd ||
-	    req2->rq_dev != req1->rq_dev ||
-	    req2->sector != req1->sector + req1->current_nr_sectors ||
-	    req2->current_nr_sectors != req1->current_nr_sectors)
-		return 0;
-	if (pardisk_num(req1) != pardisk_num(req2))
-		return 0;
-	return 1;
-}
-
-static void ddv_request1(void)
-{
-	struct request *req,*req1,*req2;
-	unsigned offset,len,req_num,mlist,bnum,available=0;
-	static unsigned mptrs[MAX_BNUM];
-	unsigned cell;
-
-	if (in_request > REQUEST_HIGH)
-		return;
-
-	next_request = get_request_queue(next_request);
-
-	while ((req = next_request)) {
-		int minor;
-
-		if (in_request >= MAX_REQUEST)
-			return;
-
-		if (in_request>1 && req_queued<REQUEST_LOW)
-			return;
-	
-		/* make sure we have room for a request */
-		available = ddv_mlist_available();
-		if (available < 1) return;
-		if (available > MAX_BNUM)
-			available = MAX_BNUM;
-
-		offset = req->sector;
-		len = req->current_nr_sectors;
-		minor = MINOR(req->rq_dev);
-		  
-		mptrs[0] = (int)req->buffer;
-
-		for (bnum=1,req1=req,req2=req->next;
-		     req2 && bnum<available && contiguous(req1,req2);
-		     req1=req2,req2=req2->next) {
-			mptrs[bnum++] = (int)req2->buffer;
-		}
-
-		next_request = req2;
-
-
-		req_queued -= bnum;
-		ddv_stats.blocks += bnum;
-		ddv_stats.rq_started += bnum;
-
-		if (req->cmd == READ) {
-			ddv_stats.reads++;
-			ddv_stats.sectors_read += len*bnum;
-		} else {
-			ddv_stats.writes++;
-			ddv_stats.sectors_written += len*bnum;
-		}
-
-		if (minor >= PARDISK_BASE) {
-			/* translate the request to the normal partition */
-			unsigned stripe;
-			minor -= PARDISK_BASE;
-
-			stripe = offset >> STRIPE_SHIFT;
-			stripe /= num_options;
-			offset = (stripe << STRIPE_SHIFT) + 
-				(offset & ((1<<STRIPE_SHIFT)-1));
-#if AIR_DISK 
-			/* like an air-guitar :-) */
-			complete_request(req,bnum);
-			continue;
-#endif
-		}
-
-		if ((cell=pardisk_num(req)) != this_option) {
-			/* its a remote request */
-			struct remote_request *rem;
-			unsigned *remlist;
-			unsigned size = sizeof(*rem) + sizeof(int)*bnum;
-
-			rem = (struct remote_request *)kmalloc(size,GFP_ATOMIC);
-			if (!rem) {
-				/* hopefully we can get it on the next go */
-				return;
-			}
-			remlist = (unsigned *)(rem+1);
-			
-			rem->u.fn = ddv_rem_queue;
-			rem->cell = this_option;
-			rem->bnum = bnum;
-			rem->req = *req;
-			rem->reqp = req;
-			rem->req.rq_dev = MKDEV(MAJOR_NR,minor);
-			rem->req.sector = offset;
-			memcpy(remlist,mptrs,sizeof(mptrs[0])*bnum);
-			
-			if (tnet_rpc(cell,rem,size,1) != 0) {
-				kfree_s(rem,size);
-				return;
-			}
-		} else {
-			/* its a local request */
-			if ((mlist = ddv_get_mlist(mptrs,bnum)) == -1) {
-				ddv_stats.errors++;
-				panic("ddv: mlist corrupted");
-			}
-
-			req_num = RTable->cell_pointer;
-			RTable->async_info[req_num].status = 
-				req->cmd==READ?DDV_RAWREAD_REQ:DDV_RAWWRITE_REQ;
-			RTable->async_info[req_num].bnum = bnum;
-			RTable->async_info[req_num].argv[0] = mlist;
-			RTable->async_info[req_num].argv[1] = len;
-			RTable->async_info[req_num].argv[2] = offset + 
-				partition_tables[minor].start_sect;
-			RTable->async_info[req_num].argv[3] = bnum;
-			RTable->async_info[req_num].argv[7] = (unsigned)req;
-			RTable->cell_pointer = INC_T(RTable->cell_pointer);
-			
-		}
-
-		in_request++;	
-	}
-}
-
-
-static void ddv_request(request_queue_t * q)
-{
-	cli();
-	ddv_request1();
-	sti();
-}
-
-
-static void check_printbufs(void)
-{  
-	int i;
-
-	if (!PrintBufs) return;
-
-	while (PrintBufs->option_counter != PrintBufs->cell_counter) {
-		i = PrintBufs->cell_counter;
-		printk("opiu (%d): ",i); 
-		if (((unsigned)PrintBufs->bufs[i].fmt) > 0x100000)
-			printk("Error: bad format in printk at %p\n", 
-			       PrintBufs->bufs[i].fmt);
-		else
-			printk(PrintBufs->bufs[i].fmt + OPIBUS_BASE,
-			       PrintBufs->bufs[i].args[0],
-			       PrintBufs->bufs[i].args[1],
-			       PrintBufs->bufs[i].args[2],
-			       PrintBufs->bufs[i].args[3],
-			       PrintBufs->bufs[i].args[4],
-			       PrintBufs->bufs[i].args[5]);
-		if (++PrintBufs->cell_counter == PRINT_BUFS)
-			PrintBufs->cell_counter = 0;
-	}
-}
-
-static void ddv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned long flags;
-	save_flags(flags); cli();
-	OPT_IO(IRC1) = 0x80000000;
-
-	check_printbufs();
-	check_completion();
-
-	ddv_request1();
-	restore_flags(flags);
-}
-
-static int ddv_open(struct inode * inode, struct file * filp)
-{
-	int minor = MINOR(inode->i_rdev);
-
-	if (!have_ddv_board || minor >= NUM_DDVDEVS)
-		return -ENODEV;
-
-	if (minor >= PARDISK_BASE) {
-		ddv_sect_length[minor] = ddv_sect_length[minor - PARDISK_BASE];
-		ddv_blk_length[minor] = ddv_blk_length[minor - PARDISK_BASE];
-	}
-
-	return 0;
-}
-
-
-static void ddv_open_reply(struct cap_request *creq)
-{
-	int size = creq->size - sizeof(*creq);
-	ddv_opcodep = (char *)kmalloc(size,GFP_ATOMIC);
-	read_bif(ddv_opcodep, size);
-#if DEBUG
-	printk("received opiu kernel of size %d\n",size);
-#endif
-	if (size == 0)
-		have_ddv_board = 0;
-	wake_up(&busy_wait);	
-}
-
-extern struct block_device_operations ddv_fops;
-
-static void ddv_load_opiu(void)
-{
-	int i;
-	struct cap_request creq;
-
-	/* if the opiu kernel is already loaded then we don't do anything */
-	if (!have_ddv_board || opiu_kernel_loaded)
-		return;
-  
-	bif_register_request(REQ_DDVOPEN,ddv_open_reply);
-
-	/* send the open request to the front end */
-	creq.cid = mpp_cid();
-	creq.type = REQ_DDVOPEN;
-	creq.header = 0;
-	creq.size = sizeof(creq);
-	
-	bif_queue(&creq,0,0);
-	
-	ddv_set_optadr();	
-
-	while (!ddv_opcodep)
-		sleep_on(&busy_wait);
-
-	if (!have_ddv_board)
-		return;
-
-	ddv_load_kernel(ddv_opcodep);
-	
-	kfree(ddv_opcodep);
-	ddv_opcodep = NULL;
-	
-	if (ddv_restart_cpu()) 
-		return;
-
-	ddv_sect_length[0] = DiskInfo->blocks;
-	ddv_blk_length[0] = DiskInfo->blocks >> 1;
-	ddv_blocksizes[0] = BLOCK_SIZE;
-
-	ddv_geometry.cylinders = ddv_sect_length[0] / 
-		(ddv_geometry.heads*ddv_geometry.sectors);
-
-	register_disk(&ddv_gendisk, MKDEV(MAJOR_NR,0), 1<<PARTN_BITS,
-			&ddv_fops, ddv_sect_length[0]);
-	
-	/* FIXME. The crap below is, well, crap. Pseudo-RAID and unsafe one */
-	for (i=0;i<PARDISK_BASE;i++) {
-		ddv_sect_length[i] = ddv_gendisk.part[i].nr_sects;
-		ddv_blk_length[i] = ddv_gendisk.part[i].nr_sects >> 1;
-	}
-
-	/* setup the parallel partitions by multiplying the normal
-	   partition by the number of options */
-	for (;i<NUM_DDVDEVS;i++) {
-		ddv_sect_length[i] = ddv_sect_length[i-PARDISK_BASE]*num_options;
-		ddv_blk_length[i] = ddv_blk_length[i-PARDISK_BASE]*num_options;
-		ddv_gendisk.part[i].start_sect = ddv_gendisk.part[i-PARDISK_BASE].start_sect;
-		ddv_gendisk.part[i].nr_sects = ddv_sect_length[i];
-	}
-
-
-	opiu_kernel_loaded = 1;       
-}
-
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- */
-static int ddv_revalidate(kdev_t dev, struct gendisk *gdev)
-{
-	int target;
-	int max_p;
-	int start;
-	int i;
-
-	target = DEVICE_NR(dev);
-
-	max_p = gdev->max_p;
-	start = target << gdev->minor_shift;
-
-	printk("ddv_revalidate dev=%d target=%d max_p=%d start=%d\n",
-	       dev,target,max_p,start);
-
-	for (i=max_p - 1; i >=0 ; i--) {
-		int minor = start + i;
-		kdev_t devi = MKDEV(gdev->major, minor);
-		sync_dev(devi);
-		invalidate_inodes(devi);
-		invalidate_buffers(devi);
-		gdev->part[minor].start_sect = 0;
-		gdev->part[minor].nr_sects = 0;
-	};
-
-	ddv_sect_length[start] = DiskInfo->blocks;
-	ddv_blk_length[start] = DiskInfo->blocks >> 1;
-
-	grok_partitions(gdev, target, 1<<PARTN_BITS, ddv_sect_length[start]);
-
-	printk("sect_length[%d]=%d blk_length[%d]=%d\n",
-	       start,ddv_sect_length[start],
-	       start,ddv_blk_length[start]);
-
-	for (i=0;i<max_p;i++) {
-		ddv_sect_length[start+i] = gdev->part[start+i].nr_sects;
-		ddv_blk_length[start+i] = gdev->part[start+i].nr_sects >> 1;
-		if (gdev->part[start+i].nr_sects)
-			printk("partition[%d] start=%d length=%d\n",i,
-			       (int)gdev->part[start+i].start_sect,
-			       (int)gdev->part[start+i].nr_sects);
-	}
-
-	return 0;
-}
-
-
-
-
-static int ddv_ioctl(struct inode *inode, struct file *file, 
-		    unsigned int cmd, unsigned long arg)
-{
-	int err;
-	struct ddv_geometry *loc = (struct ddv_geometry *) arg;
-	int dev;
-	int minor = MINOR(inode->i_rdev);
-  
-	if ((!inode) || !(inode->i_rdev))
-		return -EINVAL;
-	dev = DEVICE_NR(inode->i_rdev);
-#if DEBUG
-	printk("ddv_ioctl: cmd=%x dev=%x minor=%d\n", cmd, dev, minor);
-#endif
-	switch (cmd) {
-	case HDIO_GETGEO:
-		printk("\tHDIO_GETGEO\n");
-		if (!loc)  return -EINVAL;
-		if (put_user(ddv_geometry.heads, (char *) &loc->heads)) return -EFAULT;
-		if (put_user(ddv_geometry.sectors, (char *) &loc->sectors)) return -EFAULT;
-		if (put_user(ddv_geometry.cylinders, (short *) &loc->cylinders)) return -EFAULT;
-		if (put_user(ddv_geometry.start, (long *) &loc->start)) return -EFAULT;
-		return 0;
-  
-	case HDIO_GET_MULTCOUNT :
-		printk("\tHDIO_GET_MULTCOUNT\n");
-		return -EINVAL;
-
-	case HDIO_GET_IDENTITY :
-		printk("\tHDIO_GET_IDENTITY\n");
-		return -EINVAL;
-
-	case HDIO_GET_NOWERR :
-		printk("\tHDIO_GET_NOWERR\n");
-		return -EINVAL;
-
-	case HDIO_SET_NOWERR :
-		printk("\tHDIO_SET_NOWERR\n");
-		return -EINVAL;
-
-	case BLKRRPART:
-		printk("\tBLKRRPART\n");
-		if (!capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		return ddv_revalidate(inode->i_rdev,&ddv_gendisk);
-
-	case BLKGETSIZE:   /* Return device size */
-		if (put_user(ddv_sect_length[minor],(long *) arg)) return -EFAULT;
-#if DEBUG
-		printk("BLKGETSIZE gave %d\n",ddv_sect_length[minor]);
-#endif
-		return 0;
-    
-	default:
-		printk("ddv_ioctl: Invalid cmd=%d(0x%x)\n", cmd, cmd);
-		return -EINVAL;
-	};
-}
-
-static struct block_device_operations ddv_fops = {
-        open:		ddv_open,
-	release:	ddv_release,
-        ioctl:		ddv_ioctl,
-};
-
-
-static void ddv_status(void)
-{
-	if (!have_ddv_board) {
-		printk("no ddv board\n");
-		return;
-	}
-
-	printk("
-in_request %u   req_queued %u
-MTable:    start=%u end=%u
-Requests:  started=%u finished=%u
-Requests:  completion_pointer=%u ddv_pointer=%u cell_pointer=%u
-PrintBufs: option_counter=%u cell_counter=%u
-ddv_stats: reads=%u writes=%u blocks=%u
-ddv_stats: sectors_read=%u sectors_written=%u
-CURRENT=%p next_request=%p errors=%u
-",
-	       in_request,req_queued,
-	       RTable->start_mtable,RTable->end_mtable,
-	       ddv_stats.rq_started,ddv_stats.rq_finished,
-	       completion_pointer,RTable->ddv_pointer,RTable->cell_pointer,
-	       PrintBufs->option_counter,PrintBufs->cell_counter,
-	       ddv_stats.reads,ddv_stats.writes,ddv_stats.blocks,
-	       ddv_stats.sectors_read,ddv_stats.sectors_written,
-	       CURRENT,next_request,
-	       ddv_stats.errors);	
-}
-
-
-int ddv_init(void)
-{
-	int cid;
-	
-	cid = mpp_cid();
-	
-	if (register_blkdev(MAJOR_NR,DEVICE_NAME,&ddv_fops)) {
-		printk("ap: unable to get major %d for ap block dev\n",
-		       MAJOR_NR);
-		return -1;
-	}
-
-	printk("ddv_init: register dev %d\n", MAJOR_NR);
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
-	read_ahead[MAJOR_NR] = DDV_READ_AHEAD;
-	
-	bif_add_debug_key('d',ddv_status,"DDV status");
-	ddv_gendisk.next = gendisk_head;
-	gendisk_head = &ddv_gendisk;
-
-	num_options = mpp_num_cells();
-	this_option = mpp_cid();
-
-	kernel_thread(ddv_daemon, NULL, 0);
-
-	ddv_geninit();
-
-	return(0);
-}
-
-
-static void ddv_geninit(void)
-{
-	int i;
-	static int done = 0;
-
-	if (done)
-		printk("ddv_geninit already done!\n");
-
-	done = 1;
-
-	printk("ddv_geninit\n");
-
-	/* request interrupt line 2 */
-	if (request_irq(APOPT0_IRQ,ddv_interrupt,SA_INTERRUPT,"apddv",NULL)) {
-		printk("Failed to install ddv interrupt handler\n");
-	}
-	
-	for (i=0;i<NUM_DDVDEVS;i++) {
-		ddv_blocksizes[i] = BLOCK_SIZE;
-		ddv_sect_length[i] = 0;
-		ddv_blk_length[i] = 0;
-	}
-
-	ddv_geometry.heads = 32;
-	ddv_geometry.sectors = 32;
-	ddv_geometry.cylinders = 1;
-	ddv_geometry.start = 0;
-	
-	blksize_size[MAJOR_NR] = ddv_blocksizes;
-
-	ddv_load_opiu();
-}
-
-
-/* loadable module support */
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	int error = ddv_init();
-	if (!error)
-		printk(KERN_INFO "DDV: Loaded as module.\n");
-	return error;
-}
-
-/* Before freeing the module, invalidate all of the protected buffers! */
-void cleanup_module(void)
-{
-	int i;
-	struct gendisk ** gdp;
-
-	for (i = 0 ; i < NUM_DDVDEVS; i++)
-		invalidate_buffers(MKDEV(MAJOR_NR, i));
-
-	/* reset the opiu */
-	OPT_IO(OPIU_OP) = OPIU_RESET; 
-	OPT_IO(PRST) = PRST_IRST; 
-
-	unregister_blkdev( MAJOR_NR, DEVICE_NAME );
-	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
-		if (*gdp == &ddv_gendisk)
-			break;
-	if (*gdp)
-		*gdp = (*gdp)->next;
-	free_irq(APOPT0_IRQ, NULL);
-	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
-}
-
-#endif  /* MODULE */
-
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/ddv_util.c linux/drivers/ap1000/ddv_util.c
--- v2.3.41/linux/drivers/ap1000/ddv_util.c	Wed Dec 23 09:44:41 1998
+++ linux/drivers/ap1000/ddv_util.c	Wed Dec 31 16:00:00 1969
@@ -1,116 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/genhd.h>
-#include <asm/pgtable.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/DdvReqTable.h>
-
-
-#define GENDISK_STRUCT ddv_gendisk
-
-struct RequestTable *RTable=NULL;
-struct OPrintBufArray *PrintBufs=NULL;
-struct OAlignBufArray *AlignBufs=NULL;
-struct DiskInfo *DiskInfo=NULL;
-
-extern int ddv_length[];
-
-int ddv_mlist_available(void)
-{
-	int start = RTable->start_mtable;
-	int end = RTable->end_mtable;
-	
-	if (start >= end)
-		return (MTABLE_SIZE - start);
-	return (end+1) - start;
-}
-
-
-int ddv_get_mlist(unsigned mptr[],int bnum)
-{
-	int available = ddv_mlist_available();
-	int i;
-	int start = RTable->start_mtable;
-	
-	if (available < bnum) {
-		return -1;
-	}
-	
-	for (i = 0; i < bnum; i++) {    
-		unsigned phys = (unsigned)mmu_v2p((unsigned)mptr[i]);
-		if (phys == -1)
-			panic("bad address %x in ddv_get_mlist\n",mptr[i]);
-		RTable->mtable[RTable->start_mtable] = phys;
-		RTable->start_mtable = INC_ML(RTable->start_mtable);
-	}
-	
-	return start;
-}
-
-
-
-void ddv_load_kernel(char *opcodep)
-{
-	int tsize;
-	char *p;
-	struct exec *mhead;  
-  
-	mhead = (struct exec *)opcodep;
-	p = opcodep + sizeof(*mhead);
-	
-	tsize = (mhead->a_text + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
-	memcpy((char *)OPIBUS_BASE+mhead->a_entry,p,mhead->a_text);
-	memcpy((char *)OPIBUS_BASE+mhead->a_entry+tsize,
-	       p+mhead->a_text,mhead->a_data);
-	memset((char *)OPIBUS_BASE+mhead->a_entry+tsize+mhead->a_data,0,
-	       mhead->a_bss+PAGE_SIZE);
-	
-#ifdef DDV_DEBUG  
-	printk("CELL(%d) loaded opiu kernel of size %ld %ld %ld (%ld)\n",
-	       ap_getcid(),
-	       mhead->a_text,mhead->a_data,mhead->a_bss,mhead->a_entry);
-#endif
-}
-
-
-int ddv_restart_cpu(void)
-{ 
-	unsigned long timeout;
-
-	OPT_IO(OPIU_OP) = OPIU_RESET; 
-	OPT_IO(PRST) = PRST_IRST; 
-	if (OPT_IO(PRST) != PRST_IRST) { 
-		printk("_iu_load reset release error.\n"); 
-		return(-1);
-	}
-	for (timeout=jiffies + 10; 
-	     time_before(jiffies, timeout) || (OPT_IO(PBUF0) == 0);
-	     ) /* wait */ ;
-	if (OPT_IO(PBUF0) == 0) {
-		printk("WARNING: option kernel didn't startup\n");
-		return(-1);
-	} else {
-		printk("option kernel IU running\n");
-		DiskInfo = (struct DiskInfo *)(OPT_IO(PBUF0) + OPIBUS_BASE);
-		RTable = (struct RequestTable *)(DiskInfo->ptrs[0]+OPIBUS_BASE);
-		PrintBufs = (struct OPrintBufArray *)(DiskInfo->ptrs[1]+OPIBUS_BASE);
-		AlignBufs = (struct OAlignBufArray *)(DiskInfo->ptrs[2]+OPIBUS_BASE);
-		
-		printk("Disk capacity: %d blocks of size %d\n",
-		       (int)DiskInfo->blocks,(int)DiskInfo->blk_size);
-		
-		OPT_IO(PBUF0) = 0;
-	}
-	return(0);
-}
-
-
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/mac.c linux/drivers/ap1000/mac.c
--- v2.3.41/linux/drivers/ap1000/mac.c	Tue Feb 10 13:07:50 1998
+++ linux/drivers/ap1000/mac.c	Wed Dec 31 16:00:00 1969
@@ -1,1177 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Routines for controlling the FORMAC+
- */
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>	/* For the statistics structure. */
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/inet.h>
-#include <net/sock.h>
-
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/pgtable.h>
-
-#include "apfddi.h"
-#include "smt-types.h"
-#include "am79c830.h"
-#include "mac.h"
-#include "plc.h"
-#include "apfddi-reg.h"
-
-#define MAC_DEBUG 0
-
-/* Values for dma_state */
-#define IDLE            0
-#define XMITTING	1
-#define RECVING		2
-
-/*
- * Messages greater than this value are transferred to the FDDI send buffer
- * using DMA.
- */
-#define DMA_XMIT_THRESHOLD 64
-#define DMA_RECV_THRESHOLD 64
-
-/*
- * If the FDDI receive buffer is occupied by less than this value, then
- * sending has priority.
- */
-#define RECV_THRESHOLD (20*1024)
-
-#define DMA_RESET_MASKS ((AP_CLR_INTR_MASK<<DMA_INTR_NORMAL_SH) | \
-			 (AP_CLR_INTR_MASK<<DMA_INTR_ERROR_SH))
-
-#define DMA_INTR_REQS ((AP_INTR_REQ<<DMA_INTR_NORMAL_SH) | \
-		       (AP_INTR_REQ<<DMA_INTR_ERROR_SH))
-
-static void mac_print_state(void);
-
-typedef unsigned int	mac_status_t;
-
-static volatile struct mac_queue *mac_queue_top = NULL;
-static volatile struct mac_queue *mac_queue_bottom = NULL;
-
-struct formac_state {
-    LoopbackType loopback;
-    int	ring_op;
-    int	recv_ptr;
-    int	recv_empty;
-    int	recv_ovf;
-    int	xmit_ptr;
-    int	xmit_free;
-    int	xmit_start;
-    int	xmit_chains;
-    int	xmit_more_ptr;
-    int	frames_xmitted;
-    int	xmit_chain_start[3];
-    int frames_recvd;
-    int recv_aborted;
-    int	xmit_aborted;
-    int	wrong_bb;
-    int recv_error;
-    volatile struct mac_queue *cur_macq; /* Current queue el for send DMA   */
-    volatile struct mac_buf cur_mbuf;    /* Current mac_buf for send DMA    */
-    struct sk_buff *cur_skb;             /* skb for received packets by DMA */
-    int dma_state;
-};
-
-#define SPFRAMES_SIZE	64		/* # words for special frames area */
-#define RECV_BUF_START	SPFRAMES_SIZE
-#define RECV_BUF_END	(BUFFER_SIZE / 2 + 2048)
-#define RECV_BUF_SIZE	(RECV_BUF_END - RECV_BUF_START)
-#define XMIT_BUF_START	RECV_BUF_END
-#define XMIT_BUF_END	BUFFER_SIZE
-
-#define S2_RMT_EVENTS	(S2_CLAIM_STATE | S2_MY_CLAIM | S2_HIGHER_CLAIM | \
-			 S2_LOWER_CLAIM | S2_BEACON_STATE | S2_MY_BEACON | \
-			 S2_OTHER_BEACON | S2_RING_OP | S2_MULTIPLE_DA | \
-			 S2_TOKEN_ERR | S2_DUPL_CLAIM | S2_TRT_EXP_RECOV)
-
-struct mac_info *this_mac_info;
-struct formac_state this_mac_state;
-
-int
-mac_init(struct mac_info *mip)
-{
-    struct formac_state *msp = &this_mac_state;
-
-    bif_add_debug_key('f',mac_print_state,"show FDDI mac state");
-
-    this_mac_info = mip;
-
-    mac->cmdreg1 = C1_SOFTWARE_RESET;
-    mac->said = (mip->s_address[0] << 8) + mip->s_address[1];
-    mac->laim = (mip->l_address[0] << 8) + mip->l_address[1];
-    mac->laic = (mip->l_address[2] << 8) + mip->l_address[3];
-    mac->lail = (mip->l_address[4] << 8) + mip->l_address[5];
-    mac->sagp = (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1];
-    mac->lagm = (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1];
-    mac->lagc = (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3];
-    mac->lagl = (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5];
-    mac->tmax = mip->tmax >> 5;
-    mac->tvx = (mip->tvx - 254) / 255;	/* it's -ve, round downwards */
-    mac->treq0 = mip->treq;
-    mac->treq1 = mip->treq >> 16;
-    mac->pri0 = ~0;
-    mac->pri1 = ~0;
-    mac->pri2 = ~0;
-    mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY
-	+ 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ
-	+ M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES;
-    mac->eacb = RECV_BUF_START - 1;
-    mac->earv = XMIT_BUF_START - 1;
-    mac->eas = mac->earv;
-    mac->eaa0 = BUFFER_SIZE - 1;
-    mac->eaa1 = mac->eaa0;
-    mac->eaa2 = mac->eaa1;
-    mac->wpxsf = 0;
-    mac->rpr = RECV_BUF_START;
-    mac->wpr = RECV_BUF_START + 1;
-    mac->swpr = RECV_BUF_START;
-    mac->wpxs = mac->eas;
-    mac->swpxs = mac->eas;
-    mac->rpxs = mac->eas;
-    mac->wpxa0 = XMIT_BUF_START;
-    mac->rpxa0 = XMIT_BUF_START;
-
-    memset(msp, 0, sizeof(*msp));
-    msp->recv_ptr = RECV_BUF_START;
-    msp->recv_empty = 1;
-    msp->xmit_ptr = XMIT_BUF_START;
-    msp->xmit_free = XMIT_BUF_START + 1;
-    msp->xmit_start = XMIT_BUF_START;
-    msp->xmit_chains = 0;
-    msp->frames_xmitted = 0;
-    msp->frames_recvd = 0;
-    msp->recv_aborted = 0;
-
-    mac->mdreg1 = M1_MODE_MEMORY;
-
-    mac_make_spframes();
-
-    return 0;
-}
-
-int
-mac_inited(struct mac_info *mip)
-{
-    struct formac_state *msp = &this_mac_state;
-    mac_status_t st1, st2;
-
-    if (mac->said != (mip->s_address[0] << 8) + mip->s_address[1]
-	|| mac->laim != (mip->l_address[0] << 8) + mip->l_address[1]
-	|| mac->laic != (mip->l_address[2] << 8) + mip->l_address[3]
-	|| mac->lail != (mip->l_address[4] << 8) + mip->l_address[5]
-	|| mac->sagp != (mip->s_group_adrs[0] << 8) + mip->s_group_adrs[1]
-	|| mac->lagm != (mip->l_group_adrs[0] << 8) + mip->l_group_adrs[1]
-	|| mac->lagc != (mip->l_group_adrs[2] << 8) + mip->l_group_adrs[3]
-	|| mac->lagl != (mip->l_group_adrs[4] << 8) + mip->l_group_adrs[5])
-	return 1;
-    if ((mac->mdreg1 & ~M1_ADDET) != (M1_MODE_ONLINE | M1_SELECT_RA
-				      | M1_FULL_DUPLEX))
-	return 3;
-    if (mac->treq0 != (mip->treq & 0xffff)
-	|| mac->treq1 != ((unsigned)mip->treq >> 16))
-	return 4;
-
-    st1 = (mac->st1u << 16) + mac->st1l;
-    st2 = (mac->st2u << 16) + mac->st2l;
-    if ((st2 & S2_RING_OP) == 0)
-	return 5;
-
-    /* It's probably OK, reset some things to be safe. */
-    this_mac_info = mip;
-    *csr0 &= ~CS0_HREQ;
-    mac->tmax = mip->tmax >> 5;
-    mac->tvx = (mip->tvx - 254) / 255;	/* it's -ve, round downwards */
-    mac->pri0 = ~0;
-    mac->pri1 = ~0;
-    mac->pri2 = ~0;
-    mac->mdreg2 = /*M2_STRIP_FCS +*/ M2_CHECK_PARITY + M2_EVEN_PARITY
-	+ 3 * M2_RCV_BYTE_BDRY + M2_ENABLE_HSREQ
-	+ M2_ENABLE_NPDMA + M2_SYNC_NPDMA + M2_RECV_BAD_FRAMES;
-
-    /* clear out the receive queue */
-    mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV;
-    mac->rpr = RECV_BUF_START;
-    mac->wpr = RECV_BUF_START + 1;
-    mac->swpr = RECV_BUF_START;
-
-    memset(msp, 0, sizeof(*msp));
-    msp->recv_ptr = RECV_BUF_START;
-    msp->recv_empty = 1;
-
-    /* XXX reset transmit pointers */
-    mac->cmdreg2 = C2_ABORT_XMIT;
-    mac->cmdreg2 = C2_RESET_XMITQS;
-    mac->wpxa0 = XMIT_BUF_START;
-    mac->rpxa0 = XMIT_BUF_START;
-    msp->xmit_ptr = XMIT_BUF_START;
-    msp->xmit_free = XMIT_BUF_START + 1;
-    msp->xmit_start = XMIT_BUF_START;
-    msp->xmit_chains = 0;
-
-    mac_make_spframes();
-    mac->cmdreg1 = C1_CLR_ALL_LOCKS;
-
-    msp->frames_xmitted = 0;
-    msp->frames_recvd = 0;
-    msp->recv_aborted = 0;
-    msp->ring_op = 1;
-
-    mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_NSA;
-    mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16;
-    mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0);
-    mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF
-		    | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS
-		    | S2_NP_SIMULT_LOAD) >> 16;
-    mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME);
-
-    return 0;
-}
-
-void mac_make_spframes(void)
-{
-    volatile int *bp;
-    struct mac_info *mip = this_mac_info;
-    int sa;
-    struct formac_state *msp = &this_mac_state;
-
-    /* initialize memory to avoid parity errors */
-    *csr0 &= ~CS0_HREQ;
-    *csr1 &= ~CS1_BUF_WR_TAG;
-    for (bp = &buffer_mem[BUFFER_SIZE]; bp > &buffer_mem[XMIT_BUF_START];)
-	*--bp = 0xdeadbeef;
-    for (; bp > buffer_mem;)
-	*--bp = 0xfeedf00d;
-    buffer_mem[msp->recv_ptr] = 0;
-
-    bp = buffer_mem;
-    *bp++ = 0;			/* auto-void frame pointer (not used) */
-
-    /* make claim frame */
-    sa = bp - buffer_mem;
-    *bp++ = 0xd8000011;		/* claim frame descr. + length */
-    *bp++ = 0xc3;		/* FC value for claim frame, long addr */
-    *bp++ = (mip->l_address[0] << 24) + (mip->l_address[1] << 16)
-	+ (mip->l_address[2] << 8) + mip->l_address[3];
-    *bp++ = (mip->l_address[4] << 24) + (mip->l_address[5] << 16)
-	+ (mip->l_address[0] << 8) + mip->l_address[1];
-    *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16)
-	+ (mip->l_address[4] << 8) + mip->l_address[5];
-    *bp++ = mip->treq;
-    mac->sacl = bp - buffer_mem; /* points to pointer to claim frame */
-    *bp++ = 0xa0000000 + sa;	/* pointer to start of claim frame */
-
-    /* make beacon frame */
-    sa = bp - buffer_mem;
-    *bp++ = 0xd8000011;		/* beacon frame descr. + length */
-    *bp++ = 0xc2;		/* FC value for beacon frame, long addr */
-    *bp++ = 0;			/* DA = 0 */
-    *bp++ = (mip->l_address[0] << 8) + mip->l_address[1];
-    *bp++ = (mip->l_address[2] << 24) + (mip->l_address[3] << 16)
-	+ (mip->l_address[4] << 8) + mip->l_address[5];
-    *bp++ = 0;			/* beacon reason = failed claim */
-    mac->sabc = bp - buffer_mem;
-    *bp++ = 0xa0000000 + sa;	/* pointer to start of beacon frame */
-}
-
-void mac_reset(LoopbackType loopback)
-{
-    int mode;
-    struct formac_state *msp = &this_mac_state;
-
-    msp->loopback = loopback;
-    switch (loopback) {
-    case loop_none:
-	mode = M1_MODE_ONLINE;
-	break;
-    case loop_formac:
-	mode = M1_MODE_INT_LOOP;
-	break;
-    default:
-	mode = M1_MODE_EXT_LOOP;
-	break;
-    }
-    mac->mdreg1 = mode | M1_ADDET_NSA | M1_SELECT_RA | M1_FULL_DUPLEX;
-    mac->cmdreg1 = C1_IDLE_LISTEN;
-    mac->cmdreg1 = C1_CLR_ALL_LOCKS;
-    mac->imsk1u = ~(S1_XMIT_ABORT | S1_END_FRAME_ASYNC0) >> 16;
-    mac->imsk1l = ~(S1_PAR_ERROR_ASYNC0 | S1_QUEUE_LOCK_ASYNC0);
-    mac->imsk2u = ~(S2_RECV_COMPLETE | S2_RECV_BUF_FULL | S2_RECV_FIFO_OVF
-		    | S2_ERR_SPECIAL_FR | S2_RMT_EVENTS
-		    | S2_NP_SIMULT_LOAD) >> 16;
-    mac->imsk2l = ~(S2_RMT_EVENTS | S2_MISSED_FRAME);
-}
-
-void mac_claim(void)
-{
-    mac->cmdreg1 = C1_CLAIM_LISTEN;
-}
-
-void mac_disable(void)
-{
-    mac->mdreg1 = M1_MODE_MEMORY;
-    mac->imsk1u = ~0;
-    mac->imsk1l = ~0;
-    mac->imsk2u = ~0;
-    mac->imsk2l = ~0;
-    mac->wpr = mac->swpr + 1;
-    if (mac->wpr > mac->earv)
-	mac->wpr = mac->eacb + 1;
-    buffer_mem[mac->swpr] = 0;
-}
-
-void mac_stats(void)
-{
-    struct formac_state *msp = &this_mac_state;
-
-    if (msp->recv_ovf)
-	printk("%d receive buffer overflows\n", msp->recv_ovf);
-    if (msp->wrong_bb)
-	printk("%d frames on wrong byte bdry\n", msp->wrong_bb);
-    printk("%d frames transmitted, %d aborted\n", msp->frames_xmitted,
-	   msp->xmit_aborted);
-    printk("%d frames received, %d aborted\n", msp->frames_recvd,
-	   msp->recv_aborted);
-    printk("%d frames received with errors\n", msp->recv_error);
-}
-
-void mac_sleep(void)
-{
-    /* disable the receiver */
-    mac->mdreg1 = (mac->mdreg1 & ~M1_ADDET) | M1_ADDET_DISABLE_RECV;
-}
-
-void mac_poll(void)
-{
-    mac_status_t st1, st2;
-    struct formac_state *msp = &this_mac_state;
-    int up, f, d, l, r, e, i;
-
-    st1 = (mac->st1u << 16) + mac->st1l;
-    st2 = (mac->st2u << 16) + mac->st2l;
-
-    if (st2 & S2_NP_SIMULT_LOAD)
-	panic("NP/formac simultaneous load!!!");
-
-    up = (st2 & S2_RING_OP) != 0;
-    if (up != msp->ring_op) {
-	/* ring has come up or down */
-	msp->ring_op = up;
-	printk("mac: ring %s\n", up? "up": "down");
-	set_ring_op(up);
-    }
-
-    if (up) {
-	if (st1 & S1_XMIT_ABORT) {
-	    ++msp->xmit_aborted;
-	    if (st1 & S1_QUEUE_LOCK_ASYNC0) {
-		printk("mac: xmit queue locked, resetting xmit buffer\n");
-		mac->cmdreg2 = C2_RESET_XMITQS;	/* XXX bit gross */
-		mac->rpxa0 = XMIT_BUF_START;
-		buffer_mem[XMIT_BUF_START] = 0;
-		msp->xmit_ptr = XMIT_BUF_START;
-		msp->xmit_start = XMIT_BUF_START;
-		msp->xmit_chains = 0;
-		mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK;
-		st1 &= ~(S1_END_CHAIN_ASYNC0 | S1_END_FRAME_ASYNC0
-			 | S1_XINSTR_FULL_ASYNC0);
-	    } else
-		st1 |= S1_END_FRAME_ASYNC0;
-	} else if (st1 & S1_QUEUE_LOCK_ASYNC0) {
-	    printk("mac: xmit queue locked, why?\n");
-	    mac->cmdreg1 = C1_CLR_ASYNCQ0_LOCK;
-	}
-
-	if (st1 & S1_END_FRAME_ASYNC0) {
-	    /* advance xmit_start */
-	    e = msp->xmit_start;
-	    while (e != msp->xmit_ptr) {
-		/* find the end of the current frame */
-		f = buffer_mem[e]; /* read pointer */
-		if (f == 0)
-		    break;	/* huh?? */
-		f &= 0xffff;
-		d = buffer_mem[f]; /* read descriptor */
-		l = ((d & 0xffff) + ((d >> TD_BYTE_BDRY_LG) & 3) + 3) >> 2;
-		e = f + 1 + l;	/* index of ptr at end of frame */
-		r = mac->rpxa0;
-		if ((r <= msp->xmit_ptr && r < e && e <= msp->xmit_ptr)
-		    || (r > msp->xmit_ptr && (r < e || e <= msp->xmit_ptr)))
-		    break;	/* up to current frame */
-		/* printk("frame @ %x done\n", msp->xmit_start); */
-		msp->xmit_start = e;
-		if ((st1 & S1_XMIT_ABORT) == 0)
-		    ++msp->frames_xmitted;
-		if ((msp->xmit_chains == 1 && e == msp->xmit_ptr) ||
-		    (msp->xmit_chains > 1 && e == msp->xmit_chain_start[1])) {
-		    /* we've finished chain 0 */
-		    --msp->xmit_chains;
-		    for (i = 0; i < msp->xmit_chains; ++i)
-			msp->xmit_chain_start[i] = msp->xmit_chain_start[i+1];
-		    if (msp->xmit_chains >= 2) {
-			mac->cmdreg2 = C2_XMIT_ASYNCQ0;
-			/* printk("mac_poll: xmit chain\n"); */
-		    }
-		    if (msp->xmit_chains == 0)
-			*csr0 &= ~CS0_LED1;
-		}
-	    }
-	    /*
-	     * Now that we have a bit more space in the transmit buffer,
-	     * see if we want to put another frame in.
-	     */
-#if MAC_DEBUG
-	    printk("Removed space in transmit buffer.\n");
-#endif
-	    mac_process();
-	}
-    }
-
-    if (st2 & S2_RMT_EVENTS) {
-	rmt_event(st2);
-    }
-
-    if (st2 & S2_RECV_COMPLETE) {
-	/*
-	 * A frame has just finished arriving in the receive buffer.
-	 */
-	*csr0 |= CS0_LED2;
-	msp->recv_empty = 0;
-#if MAC_DEBUG
-	printk("Frame has just trickled in...\n");
-#endif
-	mac_process();
-    }
-
-    if (st2 & S2_RECV_BUF_FULL) {
-	/*
-	 * receive buffer overflow: reset and unlock the receive buffer.
-	 */
-/*	printk("mac: receive buffer full\n"); */
-	mac->rpr = RECV_BUF_START;
-	mac->wpr = RECV_BUF_START + 1;
-	mac->swpr = RECV_BUF_START;
-	msp->recv_ptr = RECV_BUF_START;
-	msp->recv_empty = 1;
-	buffer_mem[RECV_BUF_START] = 0;
-	mac->cmdreg1 = C1_CLR_RECVQ_LOCK;
-	++msp->recv_ovf;
-
-#if 0
-    } else if (st2 & S2_RECV_FIFO_OVF) {
-	printk("mac: receive FIFO overflow\n");
-	/* any further action required here? */
-
-    } else if (st2 & S2_MISSED_FRAME) {
-	printk("mac: missed frame\n");
-#endif
-    }
-
-    if (st2 & S2_ERR_SPECIAL_FR) {
-	printk("mac: bug: error in special frame\n");
-	mac_disable();
-    }
-}
-
-void
-mac_xmit_alloc(sp, bb)
-    struct mac_buf *sp;
-    int bb;
-{
-    int nwords;
-
-    nwords = (sp->length + bb + 3) >> 2;
-    sp->fr_start = mac_xalloc(nwords + 2);
-    sp->fr_end = sp->fr_start + nwords + 1;
-    sp->ptr = (char *) &buffer_mem[sp->fr_start + 1] + bb;
-    buffer_mem[sp->fr_start] = TD_MAGIC + (bb << TD_BYTE_BDRY_LG) + sp->length;
-}
-
-void
-mac_queue_frame(sp)
-    struct mac_buf *sp;
-{
-    struct formac_state *msp = &this_mac_state;
-
-    buffer_mem[sp->fr_end] = 0;	/* null pointer at end of frame */
-    buffer_mem[msp->xmit_ptr] = PT_MAGIC + sp->fr_start;
-    if (msp->xmit_chains <= 2) {
-	msp->xmit_chain_start[msp->xmit_chains] = msp->xmit_ptr;
-	if (msp->xmit_chains < 2)
-	    mac->cmdreg2 = C2_XMIT_ASYNCQ0;
-	++msp->xmit_chains;
-    } else {
-	buffer_mem[msp->xmit_more_ptr] |= TD_MORE;
-    }
-    msp->xmit_ptr = sp->fr_end;
-    msp->xmit_more_ptr = sp->fr_start;
-    *csr0 |= CS0_LED1;
-}
-
-int
-mac_xalloc(int nwords)
-{
-    int fr_start;
-    struct formac_state *msp = &this_mac_state;
-
-    /*
-     * Find some room in the transmit buffer.
-     */
-    fr_start = msp->xmit_free;
-    if (fr_start > msp->xmit_start) {
-	if (fr_start + nwords > XMIT_BUF_END) {
-	    /* no space at end - see if we can start again from the front */
-	    fr_start = XMIT_BUF_START;
-	    if (fr_start + nwords > msp->xmit_start)
-		panic("no space in xmit buffer (1)");
-	}
-    } else {
-	if (fr_start + nwords > msp->xmit_start)
-	    panic("no space in xmit buffer (2)");
-    }
-
-    msp->xmit_free = fr_start + nwords;
-
-    return fr_start;
-}
-
-int
-mac_recv_frame(sp)
-    struct mac_buf *sp;
-{
-    struct formac_state *msp = &this_mac_state;
-    int status, bb, orig_recv_ptr;
-
-    orig_recv_ptr = msp->recv_ptr;
-    for (;;) {
-	status = buffer_mem[msp->recv_ptr];
-	if ((status & RS_VALID) == 0) {
-	    if (status != 0) {
-		printk("recv buf out of sync: recv_ptr=%x status=%x\n",
-		       msp->recv_ptr, status);
-		printk(" rpr=%x swpr=%x, buf[rpr]=%x\n", mac->rpr, mac->swpr,
-		       buffer_mem[mac->rpr]);
-		msp->recv_ptr = mac->swpr;
-	    }
-	    *csr0 &= ~CS0_LED2;
-	    msp->recv_empty = 1;
-	    if (mac->rpr == orig_recv_ptr)
-		mac->rpr = msp->recv_ptr;
-	    return 0;
-	}
-	if (status & RS_ABORTED)
-	    ++msp->recv_aborted;
-	else {
-	    bb = (status >> RS_BYTE_BDRY_LG) & 3;
-	    if (bb != 3) {
-		++msp->wrong_bb;
-		bb = 3;
-	    }
-	    if ((status & RS_ERROR) == 0)
-		break;
-	    ++msp->recv_error;
-	    msp->recv_ptr += NWORDS((status & RS_LENGTH) + bb);
-	}
-	if (++msp->recv_ptr >= RECV_BUF_END)
-	    msp->recv_ptr -= RECV_BUF_SIZE;
-    }
-    ++msp->frames_recvd;
-    if (mac->rpr == orig_recv_ptr)
-	mac->rpr = msp->recv_ptr;
-
-    sp->fr_start = msp->recv_ptr;
-    sp->length = (status & RS_LENGTH) + bb;	/* + 4 (status) - 4 (FCS) */
-    sp->ptr = (void *) &buffer_mem[sp->fr_start];
-    if ((msp->recv_ptr += NWORDS(sp->length) + 1) >= RECV_BUF_END)
-	msp->recv_ptr -= RECV_BUF_SIZE;
-    sp->fr_end = msp->recv_ptr;
-    sp->wraplen = (RECV_BUF_END - sp->fr_start) * 4;
-    sp->wrapptr = (void *) &buffer_mem[RECV_BUF_START];
-
-    return 1;
-}
-
-void
-mac_discard_frame(sp)
-    struct mac_buf *sp;
-{
-    mac->rpr = sp->fr_end;
-}
-
-/*
- * Return the number of bytes free in the async 0 transmit queue.
- */
-int
-mac_xmit_space(void)
-{
-    struct formac_state *msp = &this_mac_state;
-    int nw;
-
-    if (msp->xmit_free > msp->xmit_start) {
-	nw = XMIT_BUF_END - msp->xmit_free;
-	if (nw < msp->xmit_start - XMIT_BUF_START)
-	    nw = msp->xmit_start - XMIT_BUF_START;
-    } else
-	nw = msp->xmit_start - msp->xmit_free;
-    return nw <= 2? 0: (nw - 2) << 2;
-}
-
-/*
- * Return the number of bytes of frames available in the receive queue.
- */
-int
-mac_recv_level(void)
-{
-    int nw;
-
-    nw = mac->swpr - mac->rpr;
-    if (nw < 0)
-	nw += mac->earv - mac->eacb;
-    return nw << 2;
-}
-
-/*
- * Return 1 iff all transmission has been completed, 0 otherwise.
- */
-int mac_xmit_done(void)
-{
-    struct formac_state *msp = &this_mac_state;
-
-    return msp->xmit_chains == 0;
-}
-
-/*
- * Append skbuff packet to queue.
- */
-int mac_queue_append (struct sk_buff *skb)
-{
-    struct mac_queue *el;
-    unsigned flags;
-    save_flags(flags); cli();
-
-#if MAC_DEBUG
-    printk("Appending queue element skb 0x%x\n", skb);
-#endif
-
-    if ((el = (struct mac_queue *)kmalloc(sizeof(*el), GFP_ATOMIC)) == NULL) {
-	restore_flags(flags);
-	return 1;
-    }
-    el->next = NULL;
-    el->skb = skb;
-    
-    if (mac_queue_top == NULL) {
-	mac_queue_top = mac_queue_bottom = el;
-    }
-    else {
-	mac_queue_bottom->next = el;
-	mac_queue_bottom = el;
-    }
-    restore_flags(flags);
-    return 0;
-}
-
-/*
- * If the packet originated from the same FDDI subnet as we are on,
- * there is no need to perform checksumming as FDDI will does this
- * us.  
- */
-#define CHECK_IF_CHECKSUM_REQUIRED(skb) \
-    if ((skb)->protocol == ETH_P_IP) { \
-	extern struct cap_init cap_init; \
-	int *from_ip = (int *)((skb)->data+12); \
-	int *to_ip = (int *)((skb)->data+16); \
-	if ((*from_ip & cap_init.netmask) == (*to_ip & cap_init.netmask)) \
-	    (skb)->ip_summed = CHECKSUM_UNNECESSARY; \
-    }
-
-/*
- * Try to send and/or recv frames.
- */
-void mac_process(void)
-{
-    volatile struct dma_chan *dma = (volatile struct dma_chan *) DMA3;
-    struct formac_state *msp = &this_mac_state;
-    struct mac_queue *el;
-    int nw=0, mrl = 0, fstart, send_buffer_full = 0;
-    unsigned flags;
-
-    save_flags(flags); cli();
-
-#if MAC_DEBUG
-    printk("In mac_process()\n");
-#endif
-
-    /*
-     * Check if the DMA is being used.
-     */
-    if (msp->dma_state != IDLE) {
-	restore_flags(flags);
-	return;
-    }
-
-    while (mac_queue_top != NULL  || /* Something to transmit */
-	   (mrl = mac_recv_level()) > 0) {  /* Frames in receive buffer */
-	send_buffer_full = 0;
-#if MAC_DEBUG
-	printk("mac_process(): something to do... mqt %x mrl is %d\n", 
-	       mac_queue_top, mrl);
-#endif
-	if (mac_queue_top != NULL && mrl < RECV_THRESHOLD) {
-	    el = (struct mac_queue *)mac_queue_top;
-
-	    /*
-	     * Check there is enough space in the FDDI send buffer.
-	     */
-	    if (mac_xmit_space() < el->skb->len) {
-#if MAC_DEBUG
-		printk("process_queue(): FDDI send buffer is full\n");
-#endif
-		send_buffer_full = 1;
-	    }
-	    else {
-#if MAC_DEBUG
-		printk("mac_process(): sending a frame\n");
-#endif
-		/*
-		 * Update mac_queue_top.
-		 */
-		mac_queue_top = mac_queue_top->next;
-
-		/*
-		 * Allocate space in the FDDI send buffer.
-		 */
-		msp->cur_mbuf.length = el->skb->len-3;
-		mac_xmit_alloc((struct mac_buf *)&msp->cur_mbuf, 3);
-
-		/*
-		 * If message size is greater than DMA_XMIT_THRESHOLD, send
-		 * using DMA, otherwise use memcpy().
-		 */
-		if (el->skb->len > DMA_XMIT_THRESHOLD) {
-		    /*
-		     * Start the DMA.
-		     */
-#if MAC_DEBUG
-		    printk("mac_process(): Starting send DMA...\n");
-#endif
-		    nw = msp->cur_mbuf.fr_end - msp->cur_mbuf.fr_start + 1;
-		    mac->wpxa0 = msp->cur_mbuf.fr_start + 1;
-		    
-		    *csr0 |= CS0_HREQ_WA0;
-		    
-		    msp->cur_macq = el;
-		    msp->dma_state = XMITTING;
-		    dma->st = DMA_DMST_RST;
-		    dma->st = DMA_RESET_MASKS;
-		    dma->hskip = 1;		/* skip = 0, count = 1 */
-		    dma->vskip = 1;		/* skip = 0, count = 1 */
-		    dma->maddr = (u_char *)
-			mmu_v2p((unsigned long)el->skb->data);
-		    dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + 
-			DMA_DCMD_TD_MD + nw;
-		    *csr0 &= ~CS0_DMA_RECV;
-		    *csr0 |= CS0_DMA_ENABLE;
-
-		    /*
-		     * Don't process any more packets since the DMA is 
-		     * being used.
-		     */
-		    break;
-		}
-		else {   /* el->skb->len <= DMA_XMIT_THRESHOLD */
-		    /*
-		     * Copy the data directly into the FDDI buffer.
-		     */
-#if MAC_DEBUG
-		    printk("mac_proces(): Copying send data...\n");
-#endif
-		    memcpy(msp->cur_mbuf.ptr - 3, el->skb->data, 
-			   ROUND4(el->skb->len));
-		    mac_queue_frame((struct mac_buf *)&msp->cur_mbuf);
-		    dev_kfree_skb(el->skb);
-		    kfree_s(el, sizeof(*el));
-		    continue;
-		}
-	    }
-
-	    /*
-	     * We have reached here if there is not enough space in the
-	     * send buffer.  Try to receive some packets instead.
-	     */
-	}
-
-	if (mac_recv_frame((struct mac_buf *)&msp->cur_mbuf)) {
-	    volatile int fc, llc_header_word2;
-	    int pkt_len = 0;
-
-#if MAC_DEBUG
-	    printk("mac_process(): Receiving frames...\n");
-#endif
-	    /* 
-	     * Get the fc, note only word accesses are allowed from the
-	     * FDDI buffers.
-	     */
-	    if (msp->cur_mbuf.wraplen > 4) {
-		fc = *(int *)(msp->cur_mbuf.ptr+4);
-	    }
-	    else {
-		/*
-		 * fc_word must be at the start of the FDDI buffer.
-		 */
-#if MAC_DEBUG
-		printk("Grabbed fc_word from wrapptr, wraplen %d\n", 
-		       msp->cur_mbuf.wraplen);
-#endif
-		fc = *(int *)msp->cur_mbuf.wrapptr;
-	    }
-	    fc &= 0xff;
-	    
-#if MAC_DEBUG
-	    printk("fc is 0x%x\n", fc);
-#endif
-	    if (fc < 0x50 || fc > 0x57) {
-		mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
-		continue;
-	    }
-
-	    /*
-	     * Determine the size of the packet data and allocate a socket
-	     * buffer.
-	     */
-	    pkt_len = msp->cur_mbuf.length - FDDI_HARDHDR_LEN;
-#if MAC_DEBUG
-	    printk("Packet of length %d\n", pkt_len);
-#endif
-	    msp->cur_skb = dev_alloc_skb(ROUND4(pkt_len));
-	    
-	    if (msp->cur_skb == NULL) {
-		printk("mac_process(): Memory squeeze, dropping packet.\n");
-		apfddi_stats->rx_dropped++;
-		restore_flags(flags);
-		return;
-	    }
-	    msp->cur_skb->dev = apfddi_device;
-
-	    /*
-	     * Hardware header isn't copied to skbuff.
-	     */
-	    msp->cur_skb->mac.raw = msp->cur_skb->data;
-	    apfddi_stats->rx_packets++;
-
-	    /*
-	     * Determine protocol from llc header.
-	     */
-	    if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) {
-		llc_header_word2 = *(int *)(msp->cur_mbuf.wrapptr + 
-					    (FDDI_HARDHDR_LEN - 
-					     msp->cur_mbuf.wraplen - 4));
-	    }
-	    else {
-		llc_header_word2 = *(int *)(msp->cur_mbuf.ptr + 
-					    FDDI_HARDHDR_LEN - 4);
-	    }
-	    msp->cur_skb->protocol = llc_header_word2 & 0xFFFF;
-#if MAC_DEBUG
-	    printk("Got protocol 0x%x\n", msp->cur_skb->protocol);
-#endif
-	    
-	    /*
-	     * Copy data into socket buffer, which may be wrapped around the 
-	     * FDDI buffer.  Use memcpy if the size of the data is less
-	     * than DMA_RECV_THRESHOLD.  Note if DMA is used, then wrap-
-	     * arounds are handled automatically.
-	     */
-	    if (pkt_len < DMA_RECV_THRESHOLD) {
-		if (msp->cur_mbuf.length < msp->cur_mbuf.wraplen) {
-		    memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), 
-			   msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, 
-			   ROUND4(pkt_len));
-		} 
-		else if (msp->cur_mbuf.wraplen < FDDI_HARDHDR_LEN) {
-#if MAC_DEBUG
-		    printk("Wrap case 2\n");
-#endif
-		    memcpy(skb_put(msp->cur_skb, ROUND4(pkt_len)), 
-			   msp->cur_mbuf.wrapptr + 
-			   (FDDI_HARDHDR_LEN - msp->cur_mbuf.wraplen),
-			   ROUND4(pkt_len));
-		} 
-		else {
-#if MAC_DEBUG
-		    printk("wrap case 3\n");
-#endif
-		    memcpy(skb_put(msp->cur_skb, 
-				   ROUND4(msp->cur_mbuf.wraplen-
-					  FDDI_HARDHDR_LEN)),
-			   msp->cur_mbuf.ptr + FDDI_HARDHDR_LEN, 
-			   ROUND4(msp->cur_mbuf.wraplen - FDDI_HARDHDR_LEN));
-		    memcpy(skb_put(msp->cur_skb, 
-				   ROUND4(msp->cur_mbuf.length - 
-					  msp->cur_mbuf.wraplen)),
-			   msp->cur_mbuf.wrapptr, 
-			   ROUND4(msp->cur_mbuf.length - 
-				  msp->cur_mbuf.wraplen));
-		}
-
-#if MAC_DEBUG
-		if (msp->cur_skb->protocol == ETH_P_IP) {
-		    dump_packet("apfddi_rx:", msp->cur_skb->data, pkt_len, 0);
-		}
-		else if (msp->cur_skb->protocol == ETH_P_ARP) {
-		    struct arphdr *arp = (struct arphdr *)msp->cur_skb->data;
-		    printk("arp->ar_op is 0x%x ar_hrd %d ar_pro 0x%x ar_hln %d ar_ln %d\n", 
-			   arp->ar_op, arp->ar_hrd, arp->ar_pro, arp->ar_hln, 
-			   arp->ar_pln);
-		    printk("sender hardware address: %x:%x:%x:%x:%x:%x\n",
-			   *((u_char *)msp->cur_skb->data+8),
-			   *((u_char *)msp->cur_skb->data+9),
-			   *((u_char *)msp->cur_skb->data+10),
-			   *((u_char *)msp->cur_skb->data+11),
-			   *((u_char *)msp->cur_skb->data+12),
-			   *((u_char *)msp->cur_skb->data+13));
-		    printk("sender IP number %d.%d.%d.%d\n", 
-			   *((u_char *)msp->cur_skb->data+14),
-			   *((u_char *)msp->cur_skb->data+15),
-			   *((u_char *)msp->cur_skb->data+16),
-			   *((u_char *)msp->cur_skb->data+17));
-		    printk("receiver hardware address: %x:%x:%x:%x:%x:%x\n",
-			   *((u_char *)msp->cur_skb->data+18),
-			   *((u_char *)msp->cur_skb->data+19),
-			   *((u_char *)msp->cur_skb->data+20),
-			   *((u_char *)msp->cur_skb->data+21),
-			   *((u_char *)msp->cur_skb->data+22),
-			   *((u_char *)msp->cur_skb->data+23));
-		    printk("receiver IP number %d.%d.%d.%d\n", 
-			   *((u_char *)msp->cur_skb->data+24),
-			   *((u_char *)msp->cur_skb->data+25),
-			   *((u_char *)msp->cur_skb->data+26),
-			   *((u_char *)msp->cur_skb->data+27));
-		}
-#endif
-		CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb);
-
-		/*
-		 * Inform the network layer of the new packet.
-		 */
-#if MAC_DEBUG
-		printk("Calling netif_rx()\n");
-#endif
-		netif_rx(msp->cur_skb);
-
-		/*
-		 * Remove frame from FDDI buffer.
-		 */
-		mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
-		continue;
-	    }
-	    else {
-		/*
-		 * Set up dma and break.
-		 */
-#if MAC_DEBUG
-		printk("mac_process(): Starting receive DMA...\n");
-#endif
-		nw = NWORDS(pkt_len);
-		msp->dma_state = RECVING;
-		*csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE);
-/*		*csr1 |= CS1_RESET_FIFO;
-		*csr1 &= ~CS1_RESET_FIFO; */
-		if ((*csr1 & CS1_FIFO_LEVEL) != 0) {
-		    int x;
-		    printk("fifo not empty! (csr1 = 0x%x) emptying...", *csr1);
-		    do {
-			x = *fifo;
-		    } while ((*csr1 & CS1_FIFO_LEVEL) != 0);
-		    printk("done\n");
-		}
-		fstart = msp->cur_mbuf.fr_start + NWORDS(FDDI_HARDHDR_LEN);
-		if (fstart >= RECV_BUF_END)
-		    fstart -= RECV_BUF_SIZE;
-		mac->rpr = fstart;
-#if MAC_DEBUG
-		printk("rpr=0x%x, nw=0x%x, stat=0x%x\n",
-		       mac->rpr, nw, buffer_mem[msp->cur_mbuf.fr_start]);
-#endif
-		dma->st = DMA_DMST_RST;
-		dma->st = DMA_RESET_MASKS;
-		dma->hskip = 1;         /* skip = 0, count = 1 */
-		dma->vskip = 1;         /* skip = 0, count = 1 */
-		dma->maddr = (u_char *)
-		    mmu_v2p((unsigned long)
-			    skb_put(msp->cur_skb, ROUND4(pkt_len)));
-		dma->cmd = DMA_DCMD_ST + DMA_DCMD_TYP_AUTO + DMA_DCMD_TD_DM
-		    + nw - 4;
-		*csr0 |= CS0_HREQ_RECV | CS0_DMA_RECV;
-		*csr0 |= CS0_DMA_ENABLE;
-#if MAC_DEBUG
-		printk("mac_process(): DMA is away!\n");
-#endif
-		break;
-	    }
-	}
-	else {
-#if MAC_DEBUG
-	    printk("mac_recv_frame failed\n");
-#endif
-	    if (msp->recv_empty && send_buffer_full)
-		break;
-	}
-    }
-    /*
-     * Update mac_queue_bottom.
-     */
-    if (mac_queue_top == NULL)
-	mac_queue_bottom = NULL;
-
-#if MAC_DEBUG
-    printk("End of mac_process()\n");
-#endif
-    restore_flags(flags);
-}
-    
-
-#define DMA_IN(reg) (*(volatile unsigned *)(reg))
-#define DMA_OUT(reg,v) (*(volatile unsigned *)(reg) = (v))
-
-/*
- * DMA completion handler.
- */
-void mac_dma_complete(void)
-{
-    volatile struct dma_chan *dma;
-    struct formac_state *msp = &this_mac_state;
-    unsigned a;
-
-    a = DMA_IN(DMA3_DMST);
-    if (!(a & DMA_INTR_REQS)) {
-	if (msp->dma_state != IDLE && (a & DMA_DMST_AC) == 0) {
-	    printk("dma completed but no interrupt!\n");
-	    msp->dma_state = IDLE;
-	}
-	return;
-    }
-
-    DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<<DMA_INTR_NORMAL_SH);
-    DMA_OUT(DMA3_DMST,AP_CLR_INTR_REQ<<DMA_INTR_ERROR_SH);
-
-    dma = (volatile struct dma_chan *) DMA3;
-
-#if MAC_DEBUG
-    printk("In mac_dma_complete\n");
-#endif
-
-    if (msp->dma_state == XMITTING && ((dma->st & DMA_DMST_AC) == 0)) {
-	/*
-	 * Transmit DMA finished.
-	 */
-	int i = 20;
-#if MAC_DEBUG
-	printk("In mac_dma_complete for transmit complete\n");
-#endif
-	while (*csr1 & CS1_FIFO_LEVEL) {
-	    if (--i <= 0) {
-		printk("csr0=0x%x csr1=0x%x: fifo not emptying\n", *csr0,
-		       *csr1);
-		return;
-	    }
-	}
-	*csr0 &= ~(CS0_HREQ | CS0_DMA_ENABLE);
-	msp->dma_state = IDLE;
-#if MAC_DEBUG
-	printk("mac_dma_complete(): Calling mac_queue_frame\n");
-#endif
-	mac_queue_frame((struct mac_buf *)&msp->cur_mbuf);
-	dev_kfree_skb(msp->cur_macq->skb);
-	kfree_s((struct mac_buf *)msp->cur_macq, sizeof(*(msp->cur_macq)));
-	msp->cur_macq = NULL;
-#if MAC_DEBUG
-	printk("mac_dma_complete(): Calling mac_process()\n");
-#endif
-	mac_process();
-#if MAC_DEBUG
-	printk("End of mac_dma_complete transmitting\n");
-#endif
-    }
-    else if (msp->dma_state == RECVING && ((dma->st & DMA_DMST_AC) == 0)) {
-	/*
-	 * Receive DMA finished.  Copy the last four words from the
-	 * fifo into the buffer, after turning off the host requests.
-	 * We do this to avoid reading past the end of frame.
-	 */
-	int *ip, i;
-
-#if MAC_DEBUG
-	printk("In mac_dma_complete for receive complete\n");
-#endif
-	msp->dma_state = IDLE;
-	ip = (int *)mmu_p2v((unsigned long)dma->cmaddr);
-
-#if MAC_DEBUG
-	printk("ip is 0x%x, skb->data is 0x%x\n", ip, msp->cur_skb->data);
-#endif
-
-	*csr0 &= ~(CS0_DMA_ENABLE | CS0_HREQ);
-
-	for (i = 0; (*csr1 & CS1_FIFO_LEVEL); ++i)
-	    ip[i] = *fifo;
-	if (i != 4)
-	    printk("mac_dma_complete(): not four words remaining in fifo?\n");
-#if MAC_DEBUG
-	printk("Copied last four words out of fifo\n");
-#endif
-	
-	/*
-	 * Remove the frame from the FDDI receive buffer.
-	 */
-	mac_discard_frame((struct mac_buf *)&msp->cur_mbuf);
-
-	CHECK_IF_CHECKSUM_REQUIRED(msp->cur_skb);
-
-	/*
-	 * Now inject the packet into the network system.
-	 */
-	netif_rx(msp->cur_skb);
-
-#if MAC_DEBUG
-	dump_packet("mac_dma_complete:", msp->cur_skb->data, 0, 0);
-#endif
-
-	/*
-	 * Check if any more frames can be processed.
-	 */
-	mac_process();
-
-#if MAC_DEBUG
-	printk("End of mac_dma_complete receiving\n");
-#endif
-    }
-#if MAC_DEBUG
-    printk("End of mac_dma_complete()\n");
-#endif
-}
-    
-static void mac_print_state(void)
-{
-    struct formac_state *msp = &this_mac_state;
-
-    printk("DMA3_DMST is 0x%x dma_state is %d\n", DMA_IN(DMA3_DMST),
-	   msp->dma_state);
-    printk("csr0 = 0x%x, csr1 = 0x%x\n", *csr0, *csr1);
-}
-
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/mac.h linux/drivers/ap1000/mac.h
--- v2.3.41/linux/drivers/ap1000/mac.h	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/mac.h	Wed Dec 31 16:00:00 1969
@@ -1,82 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Definitions of MAC state structures etc.
- */
-
-struct mac_info {
-    TimerTwosComplement	tmax;
-    TimerTwosComplement tvx;
-    TimerTwosComplement treq;
-    ShortAddressType	s_address;
-    LongAddressType	l_address;
-    ShortAddressType	s_group_adrs;
-    LongAddressType	l_group_adrs;
-    int			rcv_own_frames;
-    int			only_good_frames;
-};
-
-
-struct mac_buf {
-    struct mac_buf *next;
-    int ack;
-    int length;
-    void *ptr;
-    int wraplen;
-    void *wrapptr;
-    int fr_start;
-    int fr_end;
-};
-
-int mac_xmit_space(void);
-void mac_xmit_alloc(struct mac_buf *, int);
-void mac_queue_frame(struct mac_buf *);
-int mac_recv_frame(struct mac_buf *);
-void mac_discard_frame(struct mac_buf *);
-int mac_init(struct mac_info *mip);
-int mac_inited(struct mac_info *mip);
-void mac_reset(LoopbackType loopback);
-void mac_claim(void);
-void mac_sleep(void);
-void mac_poll(void);
-void mac_disable(void);
-void mac_make_spframes(void);
-int mac_xalloc(int nwords);
-int mac_xmit_dma(struct sk_buff *skb);
-void mac_dma_complete(void);
-void mac_process(void);
-int mac_queue_append(struct sk_buff *skb);
-
-struct dma_chan {
-    int cmd;			/* cmd << 16 + size */
-    int st;			/* status << 16 + current size */
-    int hskip;			/* hskip << 16 + hcnt */
-    int vskip;			/* vskip << 16 + vcnt */
-    unsigned char *maddr;	/* memory address */
-    unsigned char *cmaddr;	/* current memory address */
-    int ccount;			/* h_count << 16 + v_count */
-    int *tblp;			/* table pointer */
-    int *ctblp;			/* current table pointer */
-    unsigned char *hdptr;	/* header pointer */
-};
-
-#define ROUND4(x)	(((x) + 3) & -4)
-#define ROUND8(x)	(((x) + 7) & -8)
-#define ROUND16(x)	(((x) + 15) & -16)
-#define ROUNDLINE(x)	ROUND16(x)
-
-#define NWORDS(x)	(((x) + 3) >> 2)
-#define NLINES(x)	(((x) + 15) >> 4)
-
-/*
- * Queue element used to queue transmit requests on the FDDI.
- */
-struct mac_queue {
-    volatile struct mac_queue *next;
-    struct sk_buff *skb;
-};
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/plc.c linux/drivers/ap1000/plc.c
--- v2.3.41/linux/drivers/ap1000/plc.c	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/plc.c	Wed Dec 31 16:00:00 1969
@@ -1,393 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Routines for controlling the Am79c864 physical layer controller.
- *
- * This chip implements some parts of the FDDI SMT standard
- * (PCM: physical connection management, LEM: link error monitor, etc.)
- * as well as the FDDI PHY standard.
- */
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include "apfddi.h"
-#include "smt-types.h"
-#include "am79c864.h"
-#include "plc.h"
-#include "apfddi-reg.h"
-
-typedef enum {
-    off,
-    signalling,
-    doing_lct,
-    joining,
-    active
-} PlcPhase;
-    
-struct plc_state {
-    LoopbackType	loopback;
-    char		t_val[16];
-    char		r_val[16];
-    int			n;
-    PortType		peer_type;
-    PlcPhase		phase;
-};
-
-struct plc_info *this_plc_info;
-struct plc_state this_plc_state;
-
-void plc_init(struct plc_info *pip)
-{
-    int class, x;
-    struct plc_state *psp = &this_plc_state;
-
-    this_plc_info = pip;
-
-    /* first turn it off, clear registers */
-    class = pip->port_type == pt_s? CB_CLASS_S: 0;
-    plc->ctrl_b = CB_PC_STOP + class;
-    plc->intr_mask = IE_NP_ERROR;
-    x = plc->intr_event;	/* these register clear when read */
-    x = plc->viol_sym_ct;
-    x = plc->min_idle_ct;
-    x = plc->link_err_ct;
-
-    /* initialize registers */
-    plc->ctrl_a = 0;
-    plc->ctrl_b = class;
-    plc->c_min = pip->c_min >> 8;
-    plc->tl_min = pip->tl_min >> 8;
-    plc->tb_min = pip->tb_min >> 8;
-    plc->t_out = pip->t_out >> 8;
-    plc->t_scrub = pip->t_scrub >> 8;
-    plc->ns_max = pip->ns_max >> 2;
-
-    psp->phase = off;
-}
-
-int
-plc_inited(struct plc_info *pip)
-{
-    int class, x;
-    struct plc_state *psp = &this_plc_state;
-
-    class = pip->port_type == pt_s? CB_CLASS_S: 0;
-    if ((plc->ctrl_a & (CA_LOOPBACK|CA_FOT_OFF|CA_EB_LOOP|CA_LM_LOOP)) != 0)
-	return 1;
-    if ((plc->ctrl_b & (CB_CONFIG_CTRL|CB_CLASS_S|CB_PC_MAINT)) != class)
-	return 2;
-    if (plc->status_a & SA_SIG_DETECT)
-	return 3;
-    if ((plc->status_b & (SB_PCI_STATE|SB_PCM_STATE))
-	 != (SB_PCI_STATE_INSERTED|SB_PCM_STATE_ACTIVE))
-	return 4;
-
-    /* all seems OK, reset the timers and counters just to be sure */
-    plc->intr_mask = IE_NP_ERROR;
-    x = plc->intr_event;	/* these register clear when read */
-    x = plc->viol_sym_ct;
-    x = plc->min_idle_ct;
-    x = plc->link_err_ct;
-
-    plc->c_min = pip->c_min >> 8;
-    plc->tl_min = pip->tl_min >> 8;
-    plc->tb_min = pip->tb_min >> 8;
-    plc->t_out = pip->t_out >> 8;
-    plc->t_scrub = pip->t_scrub >> 8;
-    plc->ns_max = pip->ns_max >> 2;
-
-    psp->phase = active;
-    /* XXX should initialize other fields of this_plc_state */
-
-    return 0;
-}
-
-void plc_sleep(void)
-{
-}
-
-void pc_start(LoopbackType loopback)
-{
-    int x;
-    struct plc_info *pip = this_plc_info;
-    struct plc_state *psp = &this_plc_state;
-
-    /* make sure it's off */
-    plc->ctrl_b &= ~CB_PCM_CTRL;
-    plc->ctrl_b |= CB_PC_STOP;
-
-    /* set up loopback required */
-    psp->loopback = loopback;
-    x = 0;
-    switch (loopback) {
-    case loop_plc_lm:
-	x = CA_LM_LOOP;
-	break;
-    case loop_plc_eb:
-	x = CA_EB_LOOP;
-	break;
-    case loop_pdx:
-	x = CA_LOOPBACK;
-	break;
-    default:
-	x = 0;
-    }
-    plc->ctrl_a = x;
-
-    /* set up bits to be exchanged */
-    psp->t_val[0] = 0;
-    psp->t_val[1] = ((int) pip->port_type >> 1) & 1;
-    psp->t_val[2] = (int) pip->port_type & 1;
-    psp->t_val[4] = 0;		/* XXX assume we want short LCT */
-    psp->t_val[5] = 0;
-    psp->t_val[6] = 0;		/* XXX too lazy to fire up my MAC for LCT */
-    psp->t_val[8] = 0;		/* XXX don't wanna local loop */
-    psp->t_val[9] = 1;		/* gotta MAC on port output */
-
-    pc_restart();
-}
-
-void pc_restart(void)
-{
-    struct plc_state *psp = &this_plc_state;
-
-    if (psp->phase != off)
-	printk("restarting pcm\n");
-    if (psp->phase == active)
-	set_cf_join(0);		/* we're down :-( */
-
-    psp->n = 0;
-    plc->vec_length = 3 - 1;
-    plc->xmit_vector = psp->t_val[0] + (psp->t_val[1] << 1)
-	+ (psp->t_val[2] << 2);
-
-    plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_CODE;
-    plc->ctrl_b &= ~CB_PCM_CTRL;
-    plc->ctrl_b |= CB_PC_START;	/* light blue paper and stand clear */
-
-    psp->phase = signalling;
-}
-
-void pc_stop(void)
-{
-    struct plc_state *psp = &this_plc_state;
-
-    if (psp->phase == active)
-	set_cf_join(0);
-    plc->ctrl_b &= ~CB_PCM_CTRL;
-    plc->ctrl_b |= CB_PC_STOP;
-    plc->intr_mask = IE_NP_ERROR;
-    psp->phase = off;
-}
-
-void plc_poll(void)
-{
-    struct plc_state *psp = &this_plc_state;
-    int events, i;
-
-    if ((*csr0 & CS0_PHY_IRQ) == 0)
-	return;
-    events = plc->intr_event & plc->intr_mask;
-    if (events & IE_NP_ERROR) {
-	printk("plc: NP error!\n");
-    }
-    if (events & IE_PCM_BREAK) {
-	i = plc->status_b & SB_BREAK_REASON;
-	if (i > SB_BREAK_REASON_START) {
-	    if (psp->phase == signalling || psp->phase == doing_lct)
-		pcm_dump_rtcodes();
-	    printk("pcm: break reason %d\n", i);
-	    if (psp->phase != off)
-		pc_restart();
-	    /* XXX need to check for trace? */
-	}
-    }
-    if (events & IE_PCM_CODE) {
-	if (psp->phase == signalling)
-	    pcm_pseudo_code();
-	else if (psp->phase == doing_lct)
-	    pcm_lct_done();
-	else
-	    printk("XXX pcm_code interrupt in phase %d?\n", psp->phase);
-    }
-    if (events & IE_PCM_ENABLED) {
-	if (psp->phase == joining)
-	    pcm_enabled();
-	else
-	    printk("XXX pcm_enabled interrupt in phase %d?\n", psp->phase);
-    }
-    if (events & IE_TRACE_PROP) {
-	if (psp->phase == active)
-	    pcm_trace_prop();
-	else
-	    printk("XXX trace_prop interrupt in phase %d\n", psp->phase);
-    }
-}
-
-void pcm_pseudo_code(void)
-{
-    struct plc_info *pip = this_plc_info;
-    struct plc_state *psp = &this_plc_state;
-    int i, nb, lct, hislct;
-
-    /* unpack the bits from the peer */
-    nb = plc->vec_length + 1;
-    i = plc->rcv_vector;
-    do {
-	psp->r_val[psp->n++] = i & 1;
-	i >>= 1;
-    } while (--nb > 0);
-
-    /* send some more, do LCT, whatever */
-    switch (psp->n) {
-    case 3:
-	/*
-	 * Got escape flag, port type; send compatibility,
-	 * LCT duration, MAC for LCT flag.
-	 */
-	if (psp->r_val[0]) {
-	    /* help! what do I do now? */
-	    pcm_dump_rtcodes();
-	    pc_restart();
-	    break;
-	}
-	psp->peer_type = (PortType) ((psp->r_val[1] << 1) + psp->r_val[2]);
-	/* XXX we're type S, we talk to anybody */
-	psp->t_val[3] = 1;
-
-	plc->vec_length = 4 - 1;
-	plc->xmit_vector = psp->t_val[3] + (psp->t_val[4] << 1)
-	    + (psp->t_val[5] << 2) + (psp->t_val[6] << 3);
-	break;
-
-    case 7:
-	/*
-	 * Got compatibility, LCT duration, MAC for LCT flag;
-	 * time to do the LCT.
-	 */
-	lct = (psp->t_val[4] << 1) + psp->t_val[5];
-	hislct = (psp->r_val[4] << 1) + psp->r_val[5];
-	if (hislct > lct)
-	    lct = hislct;
-
-	/* set LCT duration */
-	switch (lct) {
-	case 0:
-	    plc->lc_length = pip->lc_short >> 8;
-	    plc->ctrl_b &= ~CB_LONG_LCT;
-	    break;
-	case 1:
-	    plc->lc_length = pip->lc_medium >> 8;
-	    plc->ctrl_b &= ~CB_LONG_LCT;
-	    break;
-	case 2:
-	    plc->ctrl_b |= CB_LONG_LCT;
-	    /* XXX set up a timeout for pip->lc_long */
-	    break;
-	case 3:
-	    plc->ctrl_b |= CB_LONG_LCT;
-	    /* XXX set up a timeout for pip->lc_extended */
-	    break;
-	}
-
-	/* start the LCT */
-	i = plc->link_err_ct;	/* clear the register */
-	plc->ctrl_b &= ~CB_PC_LCT;
-	/* XXX assume we're not using the MAC for LCT;
-	   if he's got a MAC, loop his stuff back, otherwise send idle. */
-	if (psp->r_val[6])
-	    plc->ctrl_b |= CB_PC_LCT_LOOP;
-	else
-	    plc->ctrl_b |= CB_PC_LCT_IDLE;
-	psp->phase = doing_lct;
-	break;
-
-    case 8:
-	/*
-	 * Got LCT result, send MAC for local loop and MAC on port
-	 * output flags.
-	 */
-	if (psp->t_val[7] || psp->r_val[7]) {
-	    printk("LCT failed, restarting.\n");
-	    /* LCT failed - do at least a medium length test next time. */
-	    if (psp->t_val[4] == 0 && psp->t_val[5] == 0)
-		psp->t_val[5] = 1;
-	    pcm_dump_rtcodes();
-	    pc_restart();
-	    break;
-	}
-	plc->vec_length = 2 - 1;
-	plc->xmit_vector = psp->t_val[8] + (psp->t_val[9] << 1);
-	break;
-
-    case 10:
-	/*
-	 * Got MAC for local loop and MAC on port output flags.
-	 * Let's join.
-	 */
-	plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_PCM_ENABLED;
-	plc->ctrl_b |= CB_PC_JOIN;
-	psp->phase = joining;
-	/* printk("pcm: joining\n"); */
-	break;
-
-    default:
-	printk("pcm_pseudo_code bug: n = %d\n", psp->n);
-    }
-}
-
-void pcm_lct_done(void)
-{
-    struct plc_state *psp = &this_plc_state;
-    int i;
-
-    i = plc->link_err_ct;
-    psp->t_val[7] = i > 0;
-    printk("pcm: lct %s (%d errors)\n", psp->t_val[7]? "failed": "passed", i);
-    plc->ctrl_b &= ~(CB_PC_LCT | CB_LONG_LCT);
-    plc->vec_length = 1 - 1;
-    plc->xmit_vector = psp->t_val[7];
-    psp->phase = signalling;
-}
-
-void pcm_dump_rtcodes(void)
-{
-    struct plc_state *psp = &this_plc_state;
-    int i;
-
-    if (psp->n > 0) {
-	printk("pcm signalling interrupted after %d bits:\nt_val:", psp->n);
-	for (i = 0; i < psp->n; ++i)
-	    printk(" %d", psp->t_val[i]);
-	printk("\nr_val:");
-	for (i = 0; i < psp->n; ++i)
-	    printk(" %d", psp->r_val[i]);
-	printk("\n");
-    }
-}
-
-void pcm_enabled(void)
-{
-    struct plc_state *psp = &this_plc_state;
-    int i;
-
-    printk("pcm: enabled\n");
-    psp->phase = active;
-    i = plc->link_err_ct;	/* clear the register */
-    /* XXX should set up LEM here */
-    /* XXX do we want to count violation symbols, minimum idle gaps,
-       or elasticity buffer errors? */
-    plc->intr_mask = IE_NP_ERROR | IE_PCM_BREAK | IE_TRACE_PROP;
-    set_cf_join(1);		/* we're up :-) */
-}
-
-void pcm_trace_prop(void)
-{
-    /* XXX help! what do I do now? */
-    pc_stop();
-}
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/plc.h linux/drivers/ap1000/plc.h
--- v2.3.41/linux/drivers/ap1000/plc.h	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/plc.h	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Definitions for PLC state structures etc.
- */
-
-struct plc_info {
-    PortType		port_type;
-    TimerTwosComplement	c_min;
-    TimerTwosComplement	tl_min;
-    TimerTwosComplement	tb_min;
-    TimerTwosComplement	t_out;
-    TimerTwosComplement	lc_short;
-    TimerTwosComplement	lc_medium;
-    TimerTwosComplement	lc_long;
-    TimerTwosComplement	lc_extended;
-    TimerTwosComplement	t_scrub;
-    TimerTwosComplement	ns_max;
-    Counter		link_errors;
-    Counter		viol_syms;
-    Counter		mini_occur;
-    int			min_idle_gap;
-    double		link_error_rate;
-};
-
-void plc_init(struct plc_info *pip);
-int plc_inited(struct plc_info *pip);
-void pc_start(LoopbackType loopback);
-void plc_sleep(void);
-void plc_poll(void);
-void pc_stop(void);
-void pc_restart(void);
-void pcm_dump_rtcodes(void);
-void pcm_pseudo_code(void);
-void pcm_lct_done(void);
-void pcm_enabled(void);
-void pcm_trace_prop(void);
-
-
-
-
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/ringbuf.c linux/drivers/ap1000/ringbuf.c
--- v2.3.41/linux/drivers/ap1000/ringbuf.c	Tue Dec  7 09:32:42 1999
+++ linux/drivers/ap1000/ringbuf.c	Wed Dec 31 16:00:00 1969
@@ -1,311 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- *  linux/drivers/ap1000/ringbuf.c
- *
- * This provides the /proc/XX/ringbuf interface to the Tnet ring buffer
- */
-#define _APLIB_
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-
-#include <asm/page.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#include <asm/ap1000/pgtapmmu.h>
-#include <asm/ap1000/apreg.h>
-#include <asm/ap1000/apservice.h>
-
-
-/* we have a small number of reserved ring buffers to ensure that at
-   least one parallel program can always run */
-#define RBUF_RESERVED 4
-#define RBUF_RESERVED_ORDER 5
-static struct {
-	char *rb_ptr;
-	char *shared_ptr;
-	int used;
-} reserved_ringbuf[RBUF_RESERVED];
-
-
-void ap_ringbuf_init(void)
-{
-	int i,j;
-	char *rb_ptr, *shared_ptr;
-	int rb_size = PAGE_SIZE * (1<<RBUF_RESERVED_ORDER);
-
-	/* preallocate some ringbuffers */
-	for (i=0;i<RBUF_RESERVED;i++) {
-		if (!(rb_ptr = (char *)__get_free_pages(GFP_ATOMIC,RBUF_RESERVED_ORDER))) {
-			printk("failed to preallocate ringbuf %d\n",i);
-			return;
-		}
-		for (j = MAP_NR(rb_ptr); j <= MAP_NR(rb_ptr+rb_size-1); j++) {
-			set_bit(PG_reserved,&mem_map[j].flags);
-		}
-
-		if (!(shared_ptr = (char *)__get_free_page(GFP_ATOMIC))) {
-			printk("failed to preallocate shared ptr %d\n",i);
-                        return;
-		}
-		set_bit(PG_reserved,&mem_map[MAP_NR(shared_ptr)].flags);
-
-		reserved_ringbuf[i].used = 0;
-		reserved_ringbuf[i].rb_ptr = rb_ptr;
-		reserved_ringbuf[i].shared_ptr = shared_ptr;
-	}
-}
-
-
-
-void exit_ringbuf(struct task_struct *tsk)
-{
-	int i;
-	
-	if (!tsk->ringbuf) return;
-	
-	if (tsk->ringbuf->ringbuf) {
-		char *rb_ptr = tsk->ringbuf->ringbuf;
-		char *shared_ptr = tsk->ringbuf->shared;
-		int order = tsk->ringbuf->order;
-		int rb_size = PAGE_SIZE * (1<<order);
-
-		for (i=0;i<RBUF_RESERVED;i++)
-			if (rb_ptr == reserved_ringbuf[i].rb_ptr) break;
-		
-		if (i < RBUF_RESERVED) {
-			reserved_ringbuf[i].used = 0;
-		} else {
-			for (i = MAP_NR(rb_ptr); i <= MAP_NR(rb_ptr+rb_size-1); i++) {
-				clear_bit(PG_reserved, &mem_map[i].flags);
-			}
-			free_pages((unsigned)rb_ptr,order);
-
-			i = MAP_NR(shared_ptr);
-			clear_bit(PG_reserved,&mem_map[i]);
-			free_page((unsigned)shared_ptr);
-		}
-	}
-
-	kfree_s(tsk->ringbuf,sizeof(*(tsk->ringbuf)));
-	tsk->ringbuf = NULL;
-}
-
-
-/*
- * map the ring buffer into users memory
- */
-static int cap_map(int rb_size)
-{
-	struct task_struct *tsk=current;
-	int i;
-	char *rb_ptr=NULL;
-	char *shared_ptr=NULL;
-	int order = 0;
-	int error,old_uid;
-
-	error = verify_area(VERIFY_WRITE,(char *)RBUF_VBASE,rb_size);
-	if (error) return error;
-	
-	if (!MPP_IS_PAR_TASK(tsk->taskid)) {
-		printk("ringbuf_mmap called from non-parallel task\n");
-		return -EINVAL;
-	}
-
-	
-	if (tsk->ringbuf) return -EINVAL;
-
-	rb_size -= RBUF_RING_BUFFER_OFFSET;
-	rb_size >>= 1;
-
-	switch (rb_size/1024) {
-	case 128:
-		order = 5;
-		break;
-	case 512:
-		order = 7;
-		break;
-	case 2048:
-		order = 9;
-		break;
-	case 8192:
-		order = 11;
-		break;
-	default:
-		printk("ringbuf_mmap with invalid size %d\n",rb_size);
-		return -EINVAL;
-	}
-	  
-	if (order == RBUF_RESERVED_ORDER) {
-		for (i=0;i<RBUF_RESERVED;i++) 
-			if (!reserved_ringbuf[i].used) {
-				rb_ptr = reserved_ringbuf[i].rb_ptr;
-				shared_ptr = reserved_ringbuf[i].shared_ptr;
-				reserved_ringbuf[i].used = 1;
-				break;
-			}
-	}
-	  
-	if (!rb_ptr) {
-		rb_ptr = (char *)__get_free_pages(GFP_USER,order);
-		if (!rb_ptr) return -ENOMEM;
-
-		for (i = MAP_NR(rb_ptr); i <= MAP_NR(rb_ptr+rb_size-1); i++) {
-			set_bit(PG_reserved,&mem_map[i].flags);
-		}
-		  
-		shared_ptr = (char *)__get_free_page(GFP_USER);
-		if (!shared_ptr)
-			return -ENOMEM;
-		set_bit(PG_reserved,&mem_map[MAP_NR(shared_ptr)].flags);
-	}
-
-	if (!rb_ptr)
-		return -ENOMEM;
-  
-	memset(rb_ptr,0,rb_size);
-	memset(shared_ptr,0,PAGE_SIZE);
-
-	if (remap_page_range(RBUF_VBASE + RBUF_RING_BUFFER_OFFSET, 
-			     mmu_v2p((unsigned)rb_ptr),
-			     rb_size,APMMU_PAGE_SHARED))
-		return -EAGAIN;
-
-	if (remap_page_range(RBUF_VBASE + RBUF_RING_BUFFER_OFFSET + rb_size, 
-			     mmu_v2p((unsigned)rb_ptr),
-			     rb_size,APMMU_PAGE_SHARED))
-		return -EAGAIN;
-  
-	/* the shared area */
-	if (remap_page_range(RBUF_VBASE + RBUF_SHARED_PAGE_OFF,
-			     mmu_v2p((unsigned)shared_ptr),
-			     PAGE_SIZE,APMMU_PAGE_SHARED))
-		return -EAGAIN;
-
-#if 0
-	/* lock the ringbuffer in memory */
-	old_uid = current->euid;
-	current->euid = 0;
-	error = sys_mlock(RBUF_VBASE,2*rb_size+RBUF_RING_BUFFER_OFFSET);
-	current->euid = old_uid;
-	if (error) {
-		printk("ringbuffer mlock failed\n");
-		return error;
-	}
-#endif
-
-	/* the queue pages */
-#define MAP_QUEUE(offset,phys) \
-	io_remap_page_range(RBUF_VBASE + offset, \
-			    phys<<PAGE_SHIFT,PAGE_SIZE,APMMU_PAGE_SHARED,0xa)
-	
-	MAP_QUEUE(RBUF_PUT_QUEUE,  0x00000);
-	MAP_QUEUE(RBUF_GET_QUEUE,  0x00001);
-	MAP_QUEUE(RBUF_SEND_QUEUE, 0x00040);
-	
-	MAP_QUEUE(RBUF_XY_QUEUE,   0x00640);
-	MAP_QUEUE(RBUF_X_QUEUE,    0x00240);
-	MAP_QUEUE(RBUF_Y_QUEUE,    0x00440);
-	MAP_QUEUE(RBUF_XYG_QUEUE,  0x00600);
-	MAP_QUEUE(RBUF_XG_QUEUE,   0x00200);
-	MAP_QUEUE(RBUF_YG_QUEUE,   0x00400);  
-	MAP_QUEUE(RBUF_CSI_QUEUE,  0x02004);  
-	MAP_QUEUE(RBUF_FOP_QUEUE,  0x02005);  
-
-#undef MAP_QUEUE
-
-	if (!tsk->ringbuf) {
-		tsk->ringbuf = (void *)kmalloc(sizeof(*(tsk->ringbuf)),GFP_ATOMIC);
-		if (!tsk->ringbuf)
-			return -ENOMEM;    
-	}
-  
-	memset(tsk->ringbuf,0,sizeof(*tsk->ringbuf));
-	tsk->ringbuf->ringbuf = rb_ptr;
-	tsk->ringbuf->shared = shared_ptr;
-	tsk->ringbuf->order = order;
-	tsk->ringbuf->write_ptr = mmu_v2p((unsigned)rb_ptr)<<1;
-	tsk->ringbuf->vaddr = RBUF_VBASE;
-  
-	memset(tsk->ringbuf->vaddr+RBUF_SHARED_PAGE_OFF,0,PAGE_SIZE);
-	{
-		struct _kernel_cap_shared *_kernel = 
-			(struct _kernel_cap_shared *)tsk->ringbuf->vaddr;
-		_kernel->rbuf_read_ptr = (rb_size>>5) - 1;
-	}
-  
-	return 0;
-}
-
-
-static int 
-ringbuf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int numcells, *phys_cells;      
-	extern struct cap_init cap_init;
-
-	switch (cmd) {
-	case CAP_GETINIT:
-		if (copy_to_user((char *)arg,(char *)&cap_init,sizeof(cap_init)))
-			return -EFAULT;
-		break;
-
-	case CAP_SYNC:
-		if (verify_area(VERIFY_READ, (void *) arg, sizeof(int)*2))
-			return -EFAULT;
-		if (get_user(numcells,(int *)arg)) return -EFAULT;
-		if (get_user((unsigned)phys_cells,
-			     ((int *)arg)+1)) return -EFAULT;
-		if (verify_area(VERIFY_READ,phys_cells,sizeof(int)*numcells))
-			return -EFAULT;
-		return ap_sync(numcells,phys_cells);
-		break;
-
-	case CAP_SETGANG:
-		{
-			int v;
-			if (get_user(v,(int *)arg)) return -EFAULT;
-			mpp_set_gang_factor(v);
-			break;
-		}
-
-	case CAP_MAP:
-		return cap_map(arg);
-		
-	default:
-		printk("unknown ringbuf ioctl %d\n",cmd);
-		return -EINVAL;
-	}
-	return 0;
-}
-
-
-static struct file_operations proc_ringbuf_operations = {
-	NULL,
-	NULL,
-	NULL,
-	NULL,		/* readdir */
-	NULL,		/* poll */
-	ringbuf_ioctl,	/* ioctl */
-	NULL,           /* mmap */
-	NULL,		/* no special open code */
-	NULL,		/* flush */
-	NULL,		/* no special release code */
-	NULL		/* can't fsync */
-};
-
-struct inode_operations proc_ringbuf_inode_operations = {
-	&proc_ringbuf_operations,	/* default base directory file-ops */
-};
diff -u --recursive --new-file v2.3.41/linux/drivers/ap1000/smt-types.h linux/drivers/ap1000/smt-types.h
--- v2.3.41/linux/drivers/ap1000/smt-types.h	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/smt-types.h	Wed Dec 31 16:00:00 1969
@@ -1,167 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- * Definitions for FDDI Station Management.
- */
-
-/*
- * FDDI-COMMON types.
- */
-
-typedef unsigned int Counter;	/* 32-bit event counter */
-
-typedef enum {
-    cp_isolated,
-    cp_local,
-    cp_secondary,
-    cp_primary,
-    cp_concatenated,
-    cp_thru
-} CurrentPath;
-
-typedef char Flag;
-
-typedef unsigned char LongAddressType[6];
-
-typedef enum {
-    pt_a,
-    pt_b,
-    pt_s,
-    pt_m,
-    pt_none
-} PortType;
-
-typedef unsigned short ResourceId;
-
-typedef int Time;		/* time in 80ns units */
-#define FDDI_TIME_UNIT	80e-9	/* 80 nanoseconds */
-#define SECS_TO_FDDI_TIME(s)	((int)((s)/FDDI_TIME_UNIT+0.99))
-
-typedef int TimerTwosComplement;
-
-/*
- * FDDI-SMT types.
- */
-typedef enum {
-    ec_Out,
-    ec_In,
-    ec_Trace,
-    ec_Leave,
-    ec_Path_Test,
-    ec_Insert,
-    ec_Check,
-    ec_Deinsert
-} ECMState;
-
-/*
- * FDDI-MAC types.
- */
-typedef enum {
-    dat_none,
-    dat_pass,
-    dat_fail
-} DupAddressTest;
-
-typedef unsigned short DupCondition;
-#define DC_MYDUP	1
-#define DC_UNADUP	2
-
-typedef unsigned short FS_Functions;
-#define FSF_FS_REPEATING	1
-#define FSF_FS_SETTING		2
-#define FSF_FS_CLEARING		4
-
-typedef unsigned char NACondition;
-#define NAC_UNACHANGE	1
-#define NAC_DNACHANGE	2
-
-typedef enum {
-    rmt_Isolated,
-    rmt_Non_Op,
-    rmt_Ring_Op,
-    rmt_Detect,
-    rmt_Non_Op_Dup,
-    rmt_Ring_Op_Dup,
-    rmt_Directed,
-    rmt_Trace
-} RMTState;
-
-typedef unsigned char ShortAddressType[2];
-
-/*
- * FDDI-PATH types.
- */
-typedef unsigned short TraceStatus;
-#define TS_TRACEINITIATED	1
-#define TS_TRACEPROPAGATED	2
-#define TS_TRACETERMINATED	4
-#define TS_TRACETIMEOUT		8
-
-/*
- * FDDI-PORT types.
- */
-typedef enum {
-    PC_Maint,
-    PC_Enable,
-    PC_Disable,
-    PC_Start,
-    PC_Stop
-} ActionType;
-
-typedef unsigned char ConnectionPolicies;
-#define PC_MAC_LCT	1
-#define PC_MAC_LOOP	2
-
-typedef enum {
-    cs_disabled,
-    cs_connecting,
-    cs_standby,
-    cs_active
-} ConnectState;
-
-typedef enum {
-    ls_qls,
-    ls_ils,
-    ls_mls,
-    ls_hls,
-    ls_pdr,
-    ls_lsu,
-    ls_nls
-} LineState;
-
-typedef enum {
-    pc_Off,
-    pc_Break,
-    pc_Trace,
-    pc_Connect,
-    pc_Next,
-    pc_Signal,
-    pc_Join,
-    pc_Verify,
-    pc_Active,
-    pc_Maint
-} PCMState;
-
-typedef enum {
-    pcw_none,
-    pcw_mm,
-    pcw_otherincompatible,
-    pcw_pathnotavailable
-} PC_Withhold;
-
-typedef enum {
-    pmd_multimode,
-    pmd_single_mode1,
-    pmd_single_mode2,
-    pmd_sonet,
-    pmd_low_cost_fiber,
-    pmd_twisted_pair,
-    pmd_unknown,
-    pmd_unspecified
-} PMDClass;
-
diff -u --recursive --new-file v2.3.41/linux/drivers/block/cmd64x.c linux/drivers/block/cmd64x.c
--- v2.3.41/linux/drivers/block/cmd64x.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/block/cmd64x.c	Mon Jan 31 23:37:19 2000
@@ -7,7 +7,7 @@
  *           on the 646U2 and not on the 646U.
  *
  * Copyright (C) 1998       Eddie C. Dost  (ecd@skynet.be)
- * Copyright (C) 1998       David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1998       David S. Miller (davem@redhat.com)
  * Copyright (C) 1999       Andre Hedrick (andre@suse.com)
  */
 
diff -u --recursive --new-file v2.3.41/linux/drivers/block/swim3.c linux/drivers/block/swim3.c
--- v2.3.41/linux/drivers/block/swim3.c	Tue Jan 11 22:31:39 2000
+++ linux/drivers/block/swim3.c	Sat Jan 29 00:17:38 2000
@@ -241,10 +241,6 @@
 			unsigned int cmd, unsigned long param);
 static int floppy_open(struct inode *inode, struct file *filp);
 static int floppy_release(struct inode *inode, struct file *filp);
-static ssize_t floppy_read(struct file *filp, char *buf,
-			   size_t count, loff_t *ppos);
-static ssize_t floppy_write(struct file *filp, const char *buf,
-			    size_t count, loff_t *ppos);
 static int floppy_check_change(kdev_t dev);
 static int floppy_revalidate(kdev_t dev);
 static int swim3_add_device(struct device_node *swims);
@@ -986,42 +982,6 @@
 
 	release_drive(fs);
 	return ret;
-}
-
-static ssize_t floppy_read(struct file *filp, char *buf,
-			   size_t count, loff_t *ppos)
-{
-	struct inode *inode = filp->f_dentry->d_inode;
-	struct floppy_state *fs;
-	int devnum = MINOR(inode->i_rdev);
-
-	if (devnum >= floppy_count)
-		return -ENODEV;
-		
-	fs = &floppy_states[devnum];
-	if (fs->ejected)
-		return -ENXIO;
-	return block_read(filp, buf, count, ppos);
-}
-
-static ssize_t floppy_write(struct file * filp, const char * buf,
-			    size_t count, loff_t *ppos)
-{
-	struct inode * inode = filp->f_dentry->d_inode;
-	struct floppy_state *fs;
-	int devnum = MINOR(inode->i_rdev);
-
-	if (devnum >= floppy_count)
-		return -ENODEV;
-	check_disk_change(inode->i_rdev);
-	fs = &floppy_states[devnum];
-	if (fs->ejected)
-		return -ENXIO;
-	if (fs->write_prot < 0)
-		fs->write_prot = swim3_readbit(fs, WRITE_PROT);
-	if (fs->write_prot)
-		return -EROFS;
-	return block_write(filp, buf, count, ppos);
 }
 
 static void floppy_off(unsigned int nr)
diff -u --recursive --new-file v2.3.41/linux/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c
--- v2.3.41/linux/drivers/block/swim_iop.c	Tue Jan 11 22:31:39 2000
+++ linux/drivers/block/swim_iop.c	Sat Jan 29 00:17:38 2000
@@ -102,10 +102,6 @@
 static void swimiop_status_update(int, struct swim_drvstatus *);
 static int swimiop_eject(struct floppy_state *fs);
 
-static ssize_t floppy_read(struct file *filp, char *buf,
-			   size_t count, loff_t *ppos);
-static ssize_t floppy_write(struct file *filp, const char *buf,
-			    size_t count, loff_t *ppos);
 static int floppy_ioctl(struct inode *inode, struct file *filp,
 			unsigned int cmd, unsigned long param);
 static int floppy_open(struct inode *inode, struct file *filp);
@@ -336,40 +332,6 @@
 	}
 	release_drive(fs);
 	return cmd->error;
-}
-
-static ssize_t floppy_read(struct file *filp, char *buf,
-			   size_t count, loff_t *ppos)
-{
-	struct inode *inode = filp->f_dentry->d_inode;
-	struct floppy_state *fs;
-	int devnum = MINOR(inode->i_rdev);
-
-	if (devnum >= floppy_count)
-		return -ENODEV;
-		
-	fs = &floppy_states[devnum];
-	if (fs->ejected)
-		return -ENXIO;
-	return block_read(filp, buf, count, ppos);
-}
-
-static ssize_t floppy_write(struct file * filp, const char * buf,
-			    size_t count, loff_t *ppos)
-{
-	struct inode * inode = filp->f_dentry->d_inode;
-	struct floppy_state *fs;
-	int devnum = MINOR(inode->i_rdev);
-
-	if (devnum >= floppy_count)
-		return -ENODEV;
-	check_disk_change(inode->i_rdev);
-	fs = &floppy_states[devnum];
-	if (fs->ejected)
-		return -ENXIO;
-	if (fs->write_prot)
-		return -EROFS;
-	return block_write(filp, buf, count, ppos);
 }
 
 static struct floppy_struct floppy_type =
diff -u --recursive --new-file v2.3.41/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c
--- v2.3.41/linux/drivers/char/agp/agpgart_be.c	Tue Jan  4 13:57:16 2000
+++ linux/drivers/char/agp/agpgart_be.c	Sat Jan 29 20:41:40 2000
@@ -232,7 +232,6 @@
 	}
 	if (curr->type != 0) {
 		agp_bridge.free_by_type(curr);
-		MOD_DEC_USE_COUNT;
 		return;
 	}
 	if (curr->page_count != 0) {
@@ -260,15 +259,23 @@
 	    agp_bridge.max_memory_agp) {
 		return NULL;
 	}
+
 	if (type != 0) {
 		new = agp_bridge.alloc_by_type(page_count, type);
 		return new;
 	}
+      	/* We always increase the module count, since free auto-decrements
+	 * it
+	 */
+
+      	MOD_INC_USE_COUNT;
+
 	scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
 
 	new = agp_create_memory(scratch_pages);
 
 	if (new == NULL) {
+	      	MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	for (i = 0; i < page_count; i++) {
@@ -286,7 +293,6 @@
 		new->page_count++;
 	}
 
-	MOD_INC_USE_COUNT;
 	return new;
 }
 
@@ -781,11 +787,13 @@
 };
 
 #define AGP_DCACHE_MEMORY 1
+#define AGP_PHYS_MEMORY   2
 
 static gatt_mask intel_i810_masks[] =
 {
 	{I810_PTE_VALID, 0},
-	{(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY}
+	{(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY},
+	{I810_PTE_VALID, 0}
 };
 
 static struct _intel_i810_private {
@@ -896,7 +904,7 @@
 		if ((type == AGP_DCACHE_MEMORY) &&
 		    (mem->type == AGP_DCACHE_MEMORY)) {
 			/* special insert */
-
+			CACHE_FLUSH();
 			for (i = pg_start;
 			     i < (pg_start + mem->page_count); i++) {
 				OUTREG32(intel_i810_private.registers,
@@ -904,20 +912,24 @@
 					 (i * 4096) | I810_PTE_LOCAL |
 					 I810_PTE_VALID);
 			}
-
+			CACHE_FLUSH();
 			agp_bridge.tlb_flush(mem);
 			return 0;
 		}
+	        if((type == AGP_PHYS_MEMORY) &&
+		   (mem->type == AGP_PHYS_MEMORY)) {
+		   goto insert;
+		}
 		return -EINVAL;
 	}
-	if (mem->is_flushed == FALSE) {
-		CACHE_FLUSH();
-		mem->is_flushed = TRUE;
-	}
+
+insert:
+   	CACHE_FLUSH();
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		OUTREG32(intel_i810_private.registers,
 			 I810_PTE_BASE + (j * 4), mem->memory[i]);
 	}
+	CACHE_FLUSH();
 
 	agp_bridge.tlb_flush(mem);
 	return 0;
@@ -955,15 +967,55 @@
 		new->page_count = pg_count;
 		new->num_scratch_pages = 0;
 		vfree(new->memory);
+	   	MOD_INC_USE_COUNT;
 		return new;
 	}
+	if(type == AGP_PHYS_MEMORY) {
+		/* The I810 requires a physical address to program
+		 * it's mouse pointer into hardware.  However the
+		 * Xserver still writes to it through the agp
+		 * aperture
+		 */
+	   	if (pg_count != 1) {
+		   	return NULL;
+		}
+	   	new = agp_create_memory(1);
+
+		if (new == NULL) {
+			return NULL;
+		}
+	   	MOD_INC_USE_COUNT;
+		new->memory[0] = agp_alloc_page();
+
+		if (new->memory[0] == 0) {
+			/* Free this structure */
+			agp_free_memory(new);
+			return NULL;
+		}
+		new->memory[0] =
+		    agp_bridge.mask_memory(
+				   virt_to_phys((void *) new->memory[0]),
+						  type);
+		new->page_count = 1;
+	   	new->num_scratch_pages = 1;
+	   	new->type = AGP_PHYS_MEMORY;
+	        new->physical = virt_to_phys((void *) new->memory[0]);
+	   	return new;
+	}
+   
 	return NULL;
 }
 
 static void intel_i810_free_by_type(agp_memory * curr)
 {
 	agp_free_key(curr->key);
+   	if(curr->type == AGP_PHYS_MEMORY) {
+	   	agp_destroy_page((unsigned long)
+				 phys_to_virt(curr->memory[0]));
+		vfree(curr->memory);
+	}
 	kfree(curr);
+   	MOD_DEC_USE_COUNT;
 }
 
 static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
@@ -1916,7 +1968,7 @@
 
 static int agp_find_max(void)
 {
-	long memory, t, index, result;
+	long memory, index, result;
 
 	memory = virt_to_phys(high_memory) >> 20;
 	index = 1;
@@ -1926,16 +1978,15 @@
 		index++;
 	}
 
-	t = (memory - maxes_table[index - 1].mem) /
-	    (maxes_table[index].mem - maxes_table[index - 1].mem);
-
 	result = maxes_table[index - 1].agp +
-	    (t * (maxes_table[index].agp - maxes_table[index - 1].agp));
+	   ( (memory - maxes_table[index - 1].mem)  *
+	     (maxes_table[index].agp - maxes_table[index - 1].agp)) /
+	   (maxes_table[index].mem - maxes_table[index - 1].mem);
 
 	printk(KERN_INFO "agpgart: Maximum main memory to use "
 	       "for agp memory: %ldM\n", result);
 	result = result << (20 - PAGE_SHIFT);
-	return result;
+        return result;
 }
 
 #define AGPGART_VERSION_MAJOR 0
diff -u --recursive --new-file v2.3.41/linux/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- v2.3.41/linux/drivers/char/agp/agpgart_fe.c	Thu Jan  6 12:57:47 2000
+++ linux/drivers/char/agp/agpgart_fe.c	Sat Jan 29 20:41:40 2000
@@ -298,7 +298,7 @@
 	agp_memory *memory;
 
 	memory = agp_allocate_memory(pg_count, type);
-
+   printk("memory : %p\n", memory);
 	if (memory == NULL) {
 		return NULL;
 	}
@@ -911,6 +911,7 @@
 		return -ENOMEM;
 	}
 	alloc.key = memory->key;
+	alloc.physical = memory->physical;
 
 	if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) {
 		agp_free_memory_wrap(memory);
diff -u --recursive --new-file v2.3.41/linux/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c
--- v2.3.41/linux/drivers/char/generic_serial.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/generic_serial.c	Mon Jan 31 10:29:16 2000
@@ -103,10 +103,6 @@
 #include "generic_serial.h"
 
 
-#ifndef MODULE
-extern void my_hd (unsigned char *ptr, int n);
-#endif
-
 static char *                  tmp_buf; 
 static DECLARE_MUTEX(tmp_buf_sem);
 
@@ -119,8 +115,8 @@
 #define gs_dprintk(f, str...) /* nothing */
 #endif
 
-#define func_enter() gs_dprintk (SX_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
-#define func_exit()  gs_dprintk (SX_DEBUG_FLOW, "gs: exit  " __FUNCTION__ "\n")
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter " __FUNCTION__ "\n")
+#define func_exit()  gs_dprintk (GS_DEBUG_FLOW, "gs: exit  " __FUNCTION__ "\n")
 
 
 
@@ -856,7 +852,6 @@
 
 	if (gs_debug & GS_DEBUG_TERMIOS) {
 		gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
-		my_hd ((unsigned char *)tiosp, sizeof (struct termios));
 	}
 
 #if 0
diff -u --recursive --new-file v2.3.41/linux/drivers/char/generic_serial.h linux/drivers/char/generic_serial.h
--- v2.3.41/linux/drivers/char/generic_serial.h	Thu Aug  5 14:47:44 1999
+++ linux/drivers/char/generic_serial.h	Mon Jan 31 10:29:16 2000
@@ -12,6 +12,8 @@
 #ifndef GENERIC_SERIAL_H
 #define GENERIC_SERIAL_H
 
+#define RS_EVENT_WRITE_WAKEUP 0
+
 struct real_driver {
   void                    (*disable_tx_interrupts) (void *);
   void                    (*enable_tx_interrupts) (void *);
@@ -75,6 +77,7 @@
 #define GS_DEBUG_TERMIOS 0x00000004
 #define GS_DEBUG_STUFF   0x00000008
 #define GS_DEBUG_CLOSE   0x00000010
+#define GS_DEBUG_FLOW    0x00000020
 
 
 void gs_put_char(struct tty_struct *tty, unsigned char ch);
diff -u --recursive --new-file v2.3.41/linux/drivers/char/joystick/joy-creative.c linux/drivers/char/joystick/joy-creative.c
--- v2.3.41/linux/drivers/char/joystick/joy-creative.c	Wed Dec  8 14:11:26 1999
+++ linux/drivers/char/joystick/joy-creative.c	Mon Jan 31 16:30:19 2000
@@ -66,7 +66,7 @@
 	int r[2], t[2], p[2];
 	int i, j, ret;
 
-	for (i = 0; i < 2; i++); {
+	for (i = 0; i < 2; i++) {
 		r[i] = buf[i] = 0;
 		p[i] = t[i] = JS_CR_MAX_STROBE;
 		p[i] += JS_CR_MAX_STROBE;
diff -u --recursive --new-file v2.3.41/linux/drivers/char/scc.h linux/drivers/char/scc.h
--- v2.3.41/linux/drivers/char/scc.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/scc.h	Mon Jan 31 23:43:51 2000
@@ -0,0 +1,613 @@
+/*
+ * atari_SCC.h: Definitions for the Am8530 Serial Communications Controller
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+#ifndef _SCC_H
+#define _SCC_H
+
+#include <linux/delay.h>
+
+/* Special configuration ioctls for the Atari SCC5380 Serial
+ * Communications Controller
+ */
+
+/* ioctl command codes */
+
+#define TIOCGATSCC	0x54c0	/* get SCC configuration */
+#define TIOCSATSCC	0x54c1	/* set SCC configuration */
+#define TIOCDATSCC	0x54c2	/* reset configuration to defaults */
+
+/* Clock sources */
+
+#define CLK_RTxC	0
+#define CLK_TRxC	1
+#define CLK_PCLK	2
+
+/* baud_bases for the common clocks in the Atari. These are the real
+ * frequencies divided by 16.
+ */
+   
+#define SCC_BAUD_BASE_TIMC	19200	/* 0.3072 MHz from TT-MFP, Timer C */
+#define SCC_BAUD_BASE_BCLK	153600	/* 2.4576 MHz */
+#define SCC_BAUD_BASE_PCLK4	229500	/* 3.6720 MHz */
+#define SCC_BAUD_BASE_PCLK	503374	/* 8.0539763 MHz */
+#define SCC_BAUD_BASE_NONE	0	/* for not connected or unused
+					 * clock sources */
+
+/* The SCC clock configuration structure */
+
+struct scc_clock_config {
+	unsigned	RTxC_base;	/* base_baud of RTxC */
+	unsigned	TRxC_base;	/* base_baud of TRxC */
+	unsigned	PCLK_base;	/* base_baud of PCLK, both channels! */
+	struct {
+		unsigned clksrc;	/* CLK_RTxC, CLK_TRxC or CLK_PCLK */
+		unsigned divisor;	/* divisor for base baud, valid values:
+					 * see below */
+	} baud_table[17];		/* For 50, 75, 110, 135, 150, 200, 300,
+					 * 600, 1200, 1800, 2400, 4800, 9600,
+					 * 19200, 38400, 57600 and 115200 bps.
+					 * The last two could be replaced by
+					 * other rates > 38400 if they're not
+					 * possible.
+					 */
+};
+
+/* The following divisors are valid:
+ *
+ *   - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use
+ *               the BRG)
+ *
+ *   - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible)
+ *
+ *   - CLK_PCLK: >= 4 and even (no direct modes, only BRG)
+ *
+ */
+
+struct scc_port {
+	struct gs_port		gs;
+	volatile unsigned char	*ctrlp;
+	volatile unsigned char	*datap;
+	int			x_char;		/* xon/xoff character */
+	int			c_dcd;
+	int			channel;
+	struct scc_port		*port_a;	/* Reference to port A and B */
+	struct scc_port		*port_b;	/*   structs for reg access  */
+};
+
+#define SCC_MAGIC	0x52696368
+
+/***********************************************************************/
+/*                                                                     */
+/*                             Register Names                          */
+/*                                                                     */
+/***********************************************************************/
+
+/* The SCC documentation gives no explicit names to the registers,
+ * they're just called WR0..15 and RR0..15. To make the source code
+ * better readable and make the transparent write reg read access (see
+ * below) possible, I christen them here with self-invented names.
+ * Note that (real) read registers are assigned numbers 16..31. WR7'
+ * has number 33.
+ */
+
+#define	COMMAND_REG		0	/* wo */
+#define	INT_AND_DMA_REG		1	/* wo */
+#define	INT_VECTOR_REG		2	/* rw, common to both channels */
+#define	RX_CTRL_REG		3	/* rw */
+#define	AUX1_CTRL_REG		4	/* rw */
+#define	TX_CTRL_REG		5	/* rw */
+#define	SYNC_ADR_REG		6	/* wo */
+#define	SYNC_CHAR_REG		7	/* wo */
+#define	SDLC_OPTION_REG		33	/* wo */
+#define	TX_DATA_REG		8	/* wo */
+#define	MASTER_INT_CTRL		9	/* wo, common to both channels */
+#define	AUX2_CTRL_REG		10	/* rw */
+#define	CLK_CTRL_REG		11	/* wo */
+#define	TIMER_LOW_REG		12	/* rw */
+#define	TIMER_HIGH_REG		13	/* rw */
+#define	DPLL_CTRL_REG		14	/* wo */
+#define	INT_CTRL_REG		15	/* rw */
+
+#define	STATUS_REG		16	/* ro */
+#define	SPCOND_STATUS_REG	17	/* wo */
+/* RR2 is WR2 for Channel A, Channel B gives vector + current status: */
+#define	CURR_VECTOR_REG		18	/* Ch. B only, Ch. A for rw */
+#define	INT_PENDING_REG		19	/* Channel A only! */
+/* RR4 is WR4, if b6(MR7') == 1 */
+/* RR5 is WR5, if b6(MR7') == 1 */
+#define	FS_FIFO_LOW_REG		22	/* ro */
+#define	FS_FIFO_HIGH_REG	23	/* ro */
+#define	RX_DATA_REG		24	/* ro */
+/* RR9 is WR3, if b6(MR7') == 1 */
+#define	DPLL_STATUS_REG		26	/* ro */
+/* RR11 is WR10, if b6(MR7') == 1 */
+/* RR12 is WR12 */
+/* RR13 is WR13 */
+/* RR14 not present */
+/* RR15 is WR15 */
+
+
+/***********************************************************************/
+/*                                                                     */
+/*                             Register Values                         */
+/*                                                                     */
+/***********************************************************************/
+
+
+/* WR0: COMMAND_REG "CR" */
+
+#define	CR_RX_CRC_RESET		0x40
+#define	CR_TX_CRC_RESET		0x80
+#define	CR_TX_UNDERRUN_RESET	0xc0
+
+#define	CR_EXTSTAT_RESET	0x10
+#define	CR_SEND_ABORT		0x18
+#define	CR_ENAB_INT_NEXT_RX	0x20
+#define	CR_TX_PENDING_RESET	0x28
+#define	CR_ERROR_RESET		0x30
+#define	CR_HIGHEST_IUS_RESET	0x38
+
+
+/* WR1: INT_AND_DMA_REG "IDR" */
+
+#define	IDR_EXTSTAT_INT_ENAB	0x01
+#define	IDR_TX_INT_ENAB		0x02
+#define	IDR_PARERR_AS_SPCOND	0x04
+
+#define	IDR_RX_INT_DISAB	0x00
+#define	IDR_RX_INT_FIRST	0x08
+#define	IDR_RX_INT_ALL		0x10
+#define	IDR_RX_INT_SPCOND	0x18
+#define	IDR_RX_INT_MASK		0x18
+
+#define	IDR_WAITREQ_RX		0x20
+#define	IDR_WAITREQ_IS_REQ	0x40
+#define	IDR_WAITREQ_ENAB	0x80
+
+
+/* WR3: RX_CTRL_REG "RCR" */
+
+#define	RCR_RX_ENAB		0x01
+#define	RCR_DISCARD_SYNC_CHARS	0x02
+#define	RCR_ADDR_SEARCH		0x04
+#define	RCR_CRC_ENAB		0x08
+#define	RCR_SEARCH_MODE		0x10
+#define	RCR_AUTO_ENAB_MODE	0x20
+
+#define	RCR_CHSIZE_MASK		0xc0
+#define	RCR_CHSIZE_5		0x00
+#define	RCR_CHSIZE_6		0x40
+#define	RCR_CHSIZE_7		0x80
+#define	RCR_CHSIZE_8		0xc0
+
+
+/* WR4: AUX1_CTRL_REG "A1CR" */
+
+#define	A1CR_PARITY_MASK	0x03
+#define	A1CR_PARITY_NONE	0x00
+#define	A1CR_PARITY_ODD		0x01
+#define	A1CR_PARITY_EVEN	0x03
+
+#define	A1CR_MODE_MASK		0x0c
+#define	A1CR_MODE_SYNCR		0x00
+#define	A1CR_MODE_ASYNC_1	0x04
+#define	A1CR_MODE_ASYNC_15	0x08
+#define	A1CR_MODE_ASYNC_2	0x0c
+
+#define	A1CR_SYNCR_MODE_MASK	0x30
+#define	A1CR_SYNCR_MONOSYNC	0x00
+#define	A1CR_SYNCR_BISYNC	0x10
+#define	A1CR_SYNCR_SDLC		0x20
+#define	A1CR_SYNCR_EXTCSYNC	0x30
+
+#define	A1CR_CLKMODE_MASK	0xc0
+#define	A1CR_CLKMODE_x1		0x00
+#define	A1CR_CLKMODE_x16	0x40
+#define	A1CR_CLKMODE_x32	0x80
+#define	A1CR_CLKMODE_x64	0xc0
+
+
+/* WR5: TX_CTRL_REG "TCR" */
+
+#define	TCR_TX_CRC_ENAB		0x01
+#define	TCR_RTS			0x02
+#define	TCR_USE_CRC_CCITT	0x00
+#define	TCR_USE_CRC_16		0x04
+#define	TCR_TX_ENAB		0x08
+#define	TCR_SEND_BREAK		0x10
+
+#define	TCR_CHSIZE_MASK		0x60
+#define	TCR_CHSIZE_5		0x00
+#define	TCR_CHSIZE_6		0x20
+#define	TCR_CHSIZE_7		0x40
+#define	TCR_CHSIZE_8		0x60
+
+#define	TCR_DTR			0x80
+
+
+/* WR7': SLDC_OPTION_REG "SOR" */
+
+#define	SOR_AUTO_TX_ENAB	0x01
+#define	SOR_AUTO_EOM_RESET	0x02
+#define	SOR_AUTO_RTS_MODE	0x04
+#define	SOR_NRZI_DISAB_HIGH	0x08
+#define	SOR_ALT_DTRREQ_TIMING	0x10
+#define	SOR_READ_CRC_CHARS	0x20
+#define	SOR_EXTENDED_REG_ACCESS	0x40
+
+
+/* WR9: MASTER_INT_CTRL "MIC" */
+
+#define	MIC_VEC_INCL_STAT	0x01
+#define	MIC_NO_VECTOR		0x02
+#define	MIC_DISAB_LOWER_CHAIN	0x04
+#define	MIC_MASTER_INT_ENAB	0x08
+#define	MIC_STATUS_HIGH		0x10
+#define	MIC_IGN_INTACK		0x20
+
+#define	MIC_NO_RESET		0x00
+#define	MIC_CH_A_RESET		0x40
+#define	MIC_CH_B_RESET		0x80
+#define	MIC_HARD_RESET		0xc0
+
+
+/* WR10: AUX2_CTRL_REG "A2CR" */
+
+#define	A2CR_SYNC_6		0x01
+#define	A2CR_LOOP_MODE		0x02
+#define	A2CR_ABORT_ON_UNDERRUN	0x04
+#define	A2CR_MARK_IDLE		0x08
+#define	A2CR_GO_ACTIVE_ON_POLL	0x10
+
+#define	A2CR_CODING_MASK	0x60
+#define	A2CR_CODING_NRZ		0x00
+#define	A2CR_CODING_NRZI	0x20
+#define	A2CR_CODING_FM1		0x40
+#define	A2CR_CODING_FM0		0x60
+
+#define	A2CR_PRESET_CRC_1	0x80
+
+
+/* WR11: CLK_CTRL_REG "CCR" */
+
+#define	CCR_TRxCOUT_MASK	0x03
+#define	CCR_TRxCOUT_XTAL	0x00
+#define	CCR_TRxCOUT_TXCLK	0x01
+#define	CCR_TRxCOUT_BRG		0x02
+#define	CCR_TRxCOUT_DPLL	0x03
+
+#define	CCR_TRxC_OUTPUT		0x04
+
+#define	CCR_TXCLK_MASK		0x18
+#define	CCR_TXCLK_RTxC		0x00
+#define	CCR_TXCLK_TRxC		0x08
+#define	CCR_TXCLK_BRG		0x10
+#define	CCR_TXCLK_DPLL		0x18
+
+#define	CCR_RXCLK_MASK		0x60
+#define	CCR_RXCLK_RTxC		0x00
+#define	CCR_RXCLK_TRxC		0x20
+#define	CCR_RXCLK_BRG		0x40
+#define	CCR_RXCLK_DPLL		0x60
+
+#define	CCR_RTxC_XTAL		0x80
+
+
+/* WR14: DPLL_CTRL_REG "DCR" */
+
+#define	DCR_BRG_ENAB		0x01
+#define	DCR_BRG_USE_PCLK	0x02
+#define	DCR_DTRREQ_IS_REQ	0x04
+#define	DCR_AUTO_ECHO		0x08
+#define	DCR_LOCAL_LOOPBACK	0x10
+
+#define	DCR_DPLL_EDGE_SEARCH	0x20
+#define	DCR_DPLL_ERR_RESET	0x40
+#define	DCR_DPLL_DISAB		0x60
+#define	DCR_DPLL_CLK_BRG	0x80
+#define	DCR_DPLL_CLK_RTxC	0xa0
+#define	DCR_DPLL_FM		0xc0
+#define	DCR_DPLL_NRZI		0xe0
+
+
+/* WR15: INT_CTRL_REG "ICR" */
+
+#define	ICR_OPTIONREG_SELECT	0x01
+#define	ICR_ENAB_BRG_ZERO_INT	0x02
+#define	ICR_USE_FS_FIFO		0x04
+#define	ICR_ENAB_DCD_INT	0x08
+#define	ICR_ENAB_SYNC_INT	0x10
+#define	ICR_ENAB_CTS_INT	0x20
+#define	ICR_ENAB_UNDERRUN_INT	0x40
+#define	ICR_ENAB_BREAK_INT	0x80
+
+
+/* RR0: STATUS_REG "SR" */
+
+#define	SR_CHAR_AVAIL		0x01
+#define	SR_BRG_ZERO		0x02
+#define	SR_TX_BUF_EMPTY		0x04
+#define	SR_DCD			0x08
+#define	SR_SYNC_ABORT		0x10
+#define	SR_CTS			0x20
+#define	SR_TX_UNDERRUN		0x40
+#define	SR_BREAK		0x80
+
+
+/* RR1: SPCOND_STATUS_REG "SCSR" */
+
+#define	SCSR_ALL_SENT		0x01
+#define	SCSR_RESIDUAL_MASK	0x0e
+#define	SCSR_PARITY_ERR		0x10
+#define	SCSR_RX_OVERRUN		0x20
+#define	SCSR_CRC_FRAME_ERR	0x40
+#define	SCSR_END_OF_FRAME	0x80
+
+
+/* RR3: INT_PENDING_REG "IPR" */
+
+#define	IPR_B_EXTSTAT		0x01
+#define	IPR_B_TX		0x02
+#define	IPR_B_RX		0x04
+#define	IPR_A_EXTSTAT		0x08
+#define	IPR_A_TX		0x10
+#define	IPR_A_RX		0x20
+
+
+/* RR7: FS_FIFO_HIGH_REG "FFHR" */
+
+#define	FFHR_CNT_MASK		0x3f
+#define	FFHR_IS_FROM_FIFO	0x40
+#define	FFHR_FIFO_OVERRUN	0x80
+
+
+/* RR10: DPLL_STATUS_REG "DSR" */
+
+#define	DSR_ON_LOOP		0x02
+#define	DSR_ON_LOOP_SENDING	0x10
+#define	DSR_TWO_CLK_MISSING	0x40
+#define	DSR_ONE_CLK_MISSING	0x80
+
+/***********************************************************************/
+/*                                                                     */
+/*                             Register Access                         */
+/*                                                                     */
+/***********************************************************************/
+
+
+/* The SCC needs 3.5 PCLK cycles recovery time between to register
+ * accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 *
+ * 125 ns = 437.5 ns. This is too short for udelay().
+ * 10/16/95: A tstb mfp.par_dt_reg takes 600ns (sure?) and thus should be
+ * quite right
+ */
+
+#define scc_reg_delay() \
+    do {			\
+	if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147)	\
+		__asm__ __volatile__ ( " nop; nop");			\
+	else if (MACH_IS_ATARI)						\
+		__asm__ __volatile__ ( "tstb %0" : : "g" (*_scc_del) : "cc" );\
+    } while (0)
+
+extern unsigned char scc_shadow[2][16];
+
+/* The following functions should relax the somehow complicated
+ * register access of the SCC. _SCCwrite() stores all written values
+ * (except for WR0 and WR8) in shadow registers for later recall. This
+ * removes the burden of remembering written values as needed. The
+ * extra work of storing the value doesn't count, since a delay is
+ * needed after a SCC access anyway. Additionally, _SCCwrite() manages
+ * writes to WR0 and WR8 differently, because these can be accessed
+ * directly with less overhead. Another special case are WR7 and WR7'.
+ * _SCCwrite automatically checks what of this registers is selected
+ * and changes b0 of WR15 if needed.
+ * 
+ * _SCCread() for standard read registers is straightforward, except
+ * for RR2 (split into two "virtual" registers: one for the value
+ * written to WR2 (from the shadow) and one for the vector including
+ * status from RR2, Ch. B) and RR3. The latter must be read from
+ * Channel A, because it reads as all zeros on Ch. B. RR0 and RR8 can
+ * be accessed directly as before.
+ * 
+ * The two inline function contain complicated switch statements. But
+ * I rely on regno and final_delay being constants, so gcc can reduce
+ * the whole stuff to just some assembler statements.
+ * 
+ * _SCCwrite and _SCCread aren't intended to be used directly under
+ * normal circumstances. The macros SCCread[_ND] and SCCwrite[_ND] are
+ * for that purpose. They assume that a local variable 'port' is
+ * declared and pointing to the port's scc_struct entry. The
+ * variants with "_NB" appended should be used if no other SCC
+ * accesses follow immediatly (within 0.5 usecs). They just skip the
+ * final delay nops.
+ * 
+ * Please note that accesses to SCC registers should only take place
+ * when interrupts are turned off (at least if SCC interrupts are
+ * enabled). Otherwise, an interrupt could interfere with the
+ * two-stage accessing process.
+ *
+ */
+
+
+static __inline__ void _SCCwrite(
+	struct scc_port *port,
+	unsigned char *shadow,
+	volatile unsigned char *_scc_del,
+	int regno,
+	unsigned char val, int final_delay )
+{
+	switch( regno ) {
+
+	  case COMMAND_REG:
+		/* WR0 can be written directly without pointing */
+		*port->ctrlp = val;
+		break;
+
+	  case SYNC_CHAR_REG:
+		/* For WR7, first set b0 of WR15 to 0, if needed */
+		if (shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT) {
+			*port->ctrlp = 15;
+			shadow[INT_CTRL_REG] &= ~ICR_OPTIONREG_SELECT;
+			scc_reg_delay();
+			*port->ctrlp = shadow[INT_CTRL_REG];
+			scc_reg_delay();
+		}
+		goto normal_case;
+		
+	  case SDLC_OPTION_REG:
+		/* For WR7', first set b0 of WR15 to 1, if needed */
+		if (!(shadow[INT_CTRL_REG] & ICR_OPTIONREG_SELECT)) {
+			*port->ctrlp = 15;
+			shadow[INT_CTRL_REG] |= ICR_OPTIONREG_SELECT;
+			scc_reg_delay();
+			*port->ctrlp = shadow[INT_CTRL_REG];
+			scc_reg_delay();
+		}
+		*port->ctrlp = 7;
+		shadow[8] = val;	/* WR7' shadowed at WR8 */
+		scc_reg_delay();
+		*port->ctrlp = val;
+		break;
+
+	  case TX_DATA_REG:		/* WR8 */
+		/* TX_DATA_REG can be accessed directly on some h/w */
+		if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147)
+		{
+			*port->ctrlp = regno;
+			scc_reg_delay();
+			*port->ctrlp = val;
+		}
+		else
+			*port->datap = val;
+		break;
+
+	  case MASTER_INT_CTRL:
+		*port->ctrlp = regno;
+		val &= 0x3f;	/* bits 6..7 are the reset commands */
+		scc_shadow[0][regno] = val;
+		scc_reg_delay();
+		*port->ctrlp = val;
+		break;
+
+	  case DPLL_CTRL_REG:
+		*port->ctrlp = regno;
+		val &= 0x1f;			/* bits 5..7 are the DPLL commands */
+		shadow[regno] = val;
+		scc_reg_delay();
+		*port->ctrlp = val;
+		break;
+
+	  case 1 ... 6:	
+	  case 10 ... 13:
+	  case 15:
+	  normal_case:
+		*port->ctrlp = regno;
+		shadow[regno] = val;
+		scc_reg_delay();
+		*port->ctrlp = val;
+		break;
+		
+	  default:
+		printk( "Bad SCC write access to WR%d\n", regno );
+		break;
+		
+	}
+
+	if (final_delay)
+		scc_reg_delay();
+}
+
+
+static __inline__ unsigned char _SCCread(
+	struct scc_port *port,
+	unsigned char *shadow,
+	volatile unsigned char *_scc_del,
+	int regno, int final_delay )
+{
+	unsigned char rv;
+
+	switch( regno ) {
+
+		/* --- real read registers --- */
+	  case STATUS_REG:
+		rv = *port->ctrlp;
+		break;
+
+	  case INT_PENDING_REG:
+		/* RR3: read only from Channel A! */
+		port = port->port_a;
+		goto normal_case;
+
+	  case RX_DATA_REG:
+		/* RR8 can be accessed directly on some h/w */
+		if (MACH_IS_MVME16x || MACH_IS_BVME6000 || MACH_IS_MVME147)
+		{
+			*port->ctrlp = 8;
+			scc_reg_delay();
+			rv = *port->ctrlp;
+		}
+		else
+			rv = *port->datap;
+		break;
+
+	  case CURR_VECTOR_REG:
+		/* RR2 (vector including status) from Ch. B */
+		port = port->port_b;
+		goto normal_case;
+		
+		/* --- reading write registers: access the shadow --- */
+	  case 1 ... 7:
+	  case 10 ... 15:
+		return shadow[regno]; /* no final delay! */
+
+		/* WR7' is special, because it is shadowed at the place of WR8 */
+	  case SDLC_OPTION_REG:
+		return shadow[8]; /* no final delay! */
+
+		/* WR9 is special too, because it is common for both channels */
+	  case MASTER_INT_CTRL:
+		return scc_shadow[0][9]; /* no final delay! */
+
+	  default:
+		printk( "Bad SCC read access to %cR%d\n", (regno & 16) ? 'R' : 'W',
+				regno & ~16 );
+		break;
+		
+	  case SPCOND_STATUS_REG:
+	  case FS_FIFO_LOW_REG:
+	  case FS_FIFO_HIGH_REG:
+	  case DPLL_STATUS_REG:
+	  normal_case:
+		*port->ctrlp = regno & 0x0f;
+		scc_reg_delay();
+		rv = *port->ctrlp;
+		break;
+		
+	}
+
+	if (final_delay)
+		scc_reg_delay();
+	return rv;
+}
+
+#define SCC_ACCESS_INIT(port)						\
+	unsigned char *_scc_shadow = &scc_shadow[port->channel][0]
+
+#define	SCCwrite(reg,val)	_SCCwrite(port,_scc_shadow,scc_del,(reg),(val),1)
+#define	SCCwrite_NB(reg,val)	_SCCwrite(port,_scc_shadow,scc_del,(reg),(val),0)
+#define	SCCread(reg)		_SCCread(port,_scc_shadow,scc_del,(reg),1)
+#define	SCCread_NB(reg)		_SCCread(port,_scc_shadow,scc_del,(reg),0)
+
+#define SCCmod(reg,and,or)	SCCwrite((reg),(SCCread(reg)&(and))|(or))
+
+#endif /* _SCC_H */
diff -u --recursive --new-file v2.3.41/linux/drivers/char/serial167.c linux/drivers/char/serial167.c
--- v2.3.41/linux/drivers/char/serial167.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/serial167.c	Mon Jan 31 10:32:04 2000
@@ -43,6 +43,7 @@
 #include <linux/tty.h>
 #include <linux/interrupt.h>
 #include <linux/serial.h>
+#include <linux/serialP.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
@@ -57,6 +58,8 @@
 #include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/mvme16xhw.h>
+#include <asm/bootinfo.h>
+#include <asm/setup.h>
 
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -144,7 +147,7 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf = 0;
-static struct semaphore tmp_buf_sem = MUTEX;
+DECLARE_MUTEX(tmp_buf_sem);
 
 /*
  * This is used to look up the divisor speeds and the timeouts
@@ -2501,8 +2504,8 @@
 		info->tqueue.data = info;
 		info->callout_termios =cy_callout_driver.init_termios;
 		info->normal_termios = cy_serial_driver.init_termios;
-		info->open_wait = 0;
-		info->close_wait = 0;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
 		/* info->session */
 		/* info->pgrp */
 /*** !!!!!!!! this may expose new bugs !!!!!!!!! *********/
@@ -2728,7 +2731,7 @@
  * that serial167_init() doesn't leave the chip non-functional.
  */
 
-void serial167_write(struct console *co, const char *str, unsigned count)
+void serial167_console_write(struct console *co, const char *str, unsigned count)
 {
 	volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
 	unsigned long flags;
@@ -2786,6 +2789,95 @@
 	base_addr[CyIER] = ier;
 
 	restore_flags(flags);
+}
+
+/* This is a hack; if there are multiple chars waiting in the chip we
+ * discard all but the last one, and return that.  The cd2401 is not really
+ * designed to be driven in polled mode.
+ */
+
+int serial167_console_wait_key(struct console *co)
+{
+	volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
+	unsigned long flags;
+	volatile u_char sink;
+	u_char ier;
+	int port;
+	int keypress = 0;
+
+	save_flags(flags); cli();
+
+	/* Ensure receiver is enabled! */
+
+	port = 0;
+	base_addr[CyCAR] = (u_char)port;
+	while (base_addr[CyCCR])
+		;
+	base_addr[CyCCR] = CyENB_RCVR;
+	ier = base_addr[CyIER];
+	base_addr[CyIER] = CyRxData;
+
+	while (!keypress) {
+		if (pcc2chip[PccSCCRICR] & 0x20)
+		{
+			/* We have an Rx int. Acknowledge it */
+			sink = pcc2chip[PccRPIACKR];
+			if ((base_addr[CyLICR] >> 2) == port) {
+				int cnt = base_addr[CyRFOC];
+				while (cnt-- > 0)
+				{
+					keypress = base_addr[CyRDR];
+				}
+				base_addr[CyREOIR] = 0;
+			}
+			else
+				base_addr[CyREOIR] = CyNOTRANS;
+		}
+	}
+
+	base_addr[CyIER] = ier;
+
+	restore_flags(flags);
+
+	return keypress;
+}
+
+
+static kdev_t serial167_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+
+static int __init serial167_console_setup(struct console *co, char *options)
+{
+	return 0;
+}
+
+
+static struct console sercons = {
+	"ttyS",
+	serial167_console_write,
+	NULL,
+	serial167_console_device,
+	serial167_console_wait_key,
+	NULL,
+	serial167_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+
+void __init serial167_console_init(void)
+{
+	if (vme_brdtype == VME_TYPE_MVME166 ||
+			vme_brdtype == VME_TYPE_MVME167 ||
+			vme_brdtype == VME_TYPE_MVME177) {
+		mvme167_serial_console_setup(0);
+		register_console(&sercons);
+	}
 }
 
 #ifdef CONFIG_REMOTE_DEBUG
diff -u --recursive --new-file v2.3.41/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.41/linux/drivers/char/tty_io.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/char/tty_io.c	Mon Jan 31 10:32:53 2000
@@ -128,6 +128,14 @@
 #ifdef CONFIG_SX
 extern int sx_init (void);
 #endif
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+extern int vme_scc_init (void);
+extern long vme_scc_console_init(void);
+#endif
+#ifdef CONFIG_SERIAL167
+extern int serial167_init(void);
+extern long serial167_console_init(void);
+#endif
 #ifdef CONFIG_8xx
 extern console_8xx_init(void);
 extern int rs_8xx_init(void);
@@ -2090,9 +2098,15 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 #ifdef CONFIG_8xx
 	console_8xx_init();
-#else 	
+#elif defined(CONFIG_SERIAL) 	
 	serial_console_init();
 #endif /* CONFIG_8xx */
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+	vme_scc_console_init();
+#endif
+#if defined(CONFIG_SERIAL167)
+	serial167_console_init();
+#endif
 #endif
 }
 
@@ -2176,6 +2190,9 @@
 #ifdef CONFIG_SERIAL
 	rs_init();
 #endif
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_BVME6000_SCC) || defined(CONFIG_MVME147_SCC)
+	vme_scc_init();
+#endif
 #ifdef CONFIG_COMPUTONE
 	ip2_init();
 #endif
@@ -2185,7 +2202,7 @@
 #ifdef CONFIG_ROCKETPORT
 	rp_init();
 #endif
-#ifdef CONFIG_MVME16x
+#ifdef CONFIG_SERIAL167
 	serial167_init();
 #endif
 #ifdef CONFIG_CYCLADES
diff -u --recursive --new-file v2.3.41/linux/drivers/char/vme_scc.c linux/drivers/char/vme_scc.c
--- v2.3.41/linux/drivers/char/vme_scc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/vme_scc.c	Mon Jan 31 10:32:04 2000
@@ -0,0 +1,1136 @@
+/*
+ * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports
+ * implementation.
+ * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk>
+ *
+ * Based on atari_SCC.c which was
+ *   Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *   Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/tqueue.h>
+#include <linux/version.h>
+#include <linux/malloc.h>
+#include <linux/miscdevice.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+
+#ifdef CONFIG_MVME147_SCC
+#include <asm/mvme147hw.h>
+#endif
+#ifdef CONFIG_MVME162_SCC
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef CONFIG_BVME6000_SCC
+#include <asm/bvme6000hw.h>
+#endif
+
+#include "generic_serial.h"
+#include "scc.h"
+
+
+#define CHANNEL_A	0
+#define CHANNEL_B	1
+
+#define SCC_MINOR_BASE	64
+
+/* Shadows for all SCC write registers */
+static unsigned char scc_shadow[2][16];
+
+/* Location to access for SCC register access delay */
+static volatile unsigned char *scc_del = NULL;
+
+/* To keep track of STATUS_REG state for detection of Ext/Status int source */
+static unsigned char scc_last_status_reg[2];
+
+/***************************** Prototypes *****************************/
+
+/* Function prototypes */
+static void scc_disable_tx_interrupts(void * ptr);
+static void scc_enable_tx_interrupts(void * ptr);
+static void scc_disable_rx_interrupts(void * ptr);
+static void scc_enable_rx_interrupts(void * ptr);
+static int  scc_get_CD(void * ptr);
+static void scc_shutdown_port(void * ptr);
+static void scc_set_real_termios(void  *ptr);
+static void scc_hungup(void  *ptr);
+static void scc_close(void  *ptr);
+static int scc_chars_in_buffer(void * ptr);
+static int scc_open(struct tty_struct * tty, struct file * filp);
+static int scc_ioctl(struct tty_struct * tty, struct file * filp,
+                     unsigned int cmd, unsigned long arg);
+static void scc_throttle(struct tty_struct *tty);
+static void scc_unthrottle(struct tty_struct *tty);
+static void scc_tx_int(int irq, void *data, struct pt_regs *fp);
+static void scc_rx_int(int irq, void *data, struct pt_regs *fp);
+static void scc_stat_int(int irq, void *data, struct pt_regs *fp);
+static void scc_spcond_int(int irq, void *data, struct pt_regs *fp);
+static void scc_setsignals(struct scc_port *port, int dtr, int rts);
+static void scc_break_ctl(struct tty_struct *tty, int break_state);
+
+static struct tty_driver scc_driver, scc_callout_driver;
+
+static struct tty_struct *scc_table[2] = { NULL, };
+static struct termios * scc_termios[2];
+static struct termios * scc_termios_locked[2];
+struct scc_port scc_ports[2];
+
+int scc_refcount;
+int scc_initialized = 0;
+
+/*---------------------------------------------------------------------------
+ * Interface from generic_serial.c back here
+ *--------------------------------------------------------------------------*/
+
+static struct real_driver scc_real_driver = {
+        scc_disable_tx_interrupts,
+        scc_enable_tx_interrupts,
+        scc_disable_rx_interrupts,
+        scc_enable_rx_interrupts,
+        scc_get_CD,
+        scc_shutdown_port,
+        scc_set_real_termios,
+        scc_chars_in_buffer,
+        scc_close,
+        scc_hungup,
+        NULL
+};
+
+
+/*----------------------------------------------------------------------------
+ * vme_scc_init() and support functions
+ *---------------------------------------------------------------------------*/
+
+static int scc_init_drivers(void)
+{
+	int error;
+
+	memset(&scc_driver, 0, sizeof(scc_driver));
+	scc_driver.magic = TTY_DRIVER_MAGIC;
+	scc_driver.driver_name = "scc";
+	scc_driver.name = "ttyS";
+	scc_driver.major = TTY_MAJOR;
+	scc_driver.minor_start = SCC_MINOR_BASE;
+	scc_driver.num = 2;
+	scc_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	scc_driver.subtype = SERIAL_TYPE_NORMAL;
+	scc_driver.init_termios = tty_std_termios;
+	scc_driver.init_termios.c_cflag =
+	  B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	scc_driver.flags = TTY_DRIVER_REAL_RAW;
+	scc_driver.refcount = &scc_refcount;
+	scc_driver.table = scc_table;
+	scc_driver.termios = scc_termios;
+	scc_driver.termios_locked = scc_termios_locked;
+
+	scc_driver.open	= scc_open;
+	scc_driver.close = gs_close;
+	scc_driver.write = gs_write;
+	scc_driver.put_char = gs_put_char;
+	scc_driver.flush_chars = gs_flush_chars;
+	scc_driver.write_room = gs_write_room;
+	scc_driver.chars_in_buffer = gs_chars_in_buffer;
+	scc_driver.flush_buffer = gs_flush_buffer;
+	scc_driver.ioctl = scc_ioctl;
+	scc_driver.throttle = scc_throttle;
+	scc_driver.unthrottle = scc_unthrottle;
+	scc_driver.set_termios = gs_set_termios;
+	scc_driver.stop = gs_stop;
+	scc_driver.start = gs_start;
+	scc_driver.hangup = gs_hangup;
+	scc_driver.break_ctl = scc_break_ctl;
+
+	scc_callout_driver = scc_driver;
+	scc_callout_driver.name = "cua";
+	scc_callout_driver.major = TTYAUX_MAJOR;
+	scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if ((error = tty_register_driver(&scc_driver))) {
+		printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n",
+		       error);
+		return 1;
+	}
+	if ((error = tty_register_driver(&scc_callout_driver))) {
+		tty_unregister_driver(&scc_driver);
+		printk(KERN_ERR "scc: Couldn't register scc callout driver, error = %d\n",
+		       error);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1).
+ */
+
+static void scc_init_portstructs(void)
+{
+	struct scc_port *port;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		port = scc_ports + i;
+		port->gs.callout_termios = tty_std_termios;
+		port->gs.normal_termios = tty_std_termios;
+		port->gs.magic = SCC_MAGIC;
+		port->gs.close_delay = HZ/2;
+		port->gs.closing_wait = 30 * HZ;
+		port->gs.rd = &scc_real_driver;
+#ifdef NEW_WRITE_LOCKING
+		port->gs.port_write_sem = MUTEX;
+#endif
+		init_waitqueue_head(&port->gs.open_wait);
+		init_waitqueue_head(&port->gs.close_wait);
+	}
+}
+
+
+#ifdef CONFIG_MVME147_SCC
+static int mvme147_scc_init(void)
+{
+	struct scc_port *port;
+
+	printk("SCC: MVME147 Serial Driver\n");
+	/* Init channel A */
+	port = &scc_ports[0];
+	port->channel = CHANNEL_A;
+	port->ctrlp = (volatile unsigned char *)M147_SCC_A_ADDR;
+	port->datap = port->ctrlp + 1;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+		            "SCC-A TX", port);
+	request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+		            "SCC-A status", port);
+	request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+		            "SCC-A RX", port);
+	request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+		            "SCC-A special cond", port);
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+		/* Set the interrupt vector */
+		SCCwrite(INT_VECTOR_REG, MVME147_IRQ_SCC_BASE);
+		/* Interrupt parameters: vector includes status, status low */
+		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+	}
+
+	/* Init channel B */
+	port = &scc_ports[1];
+	port->channel = CHANNEL_B;
+	port->ctrlp = (volatile unsigned char *)M147_SCC_B_ADDR;
+	port->datap = port->ctrlp + 1;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+		            "SCC-B TX", port);
+	request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+		            "SCC-B status", port);
+	request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+		            "SCC-B RX", port);
+	request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+		            "SCC-B special cond", port);
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+	}
+
+        /* Ensure interrupts are enabled in the PCC chip */
+        m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB;
+
+	/* Initialise the tty driver structures and register */
+	scc_init_portstructs();
+	scc_init_drivers();
+
+	return 0;
+}
+#endif
+
+
+#ifdef CONFIG_MVME162_SCC
+static int mvme162_scc_init(void)
+{
+	struct scc_port *port;
+
+	if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
+		return (-ENODEV);
+
+	printk("SCC: MVME162 Serial Driver\n");
+	/* Init channel A */
+	port = &scc_ports[0];
+	port->channel = CHANNEL_A;
+	port->ctrlp = (volatile unsigned char *)MVME_SCC_A_ADDR;
+	port->datap = port->ctrlp + 2;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+		            "SCC-A TX", port);
+	request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+		            "SCC-A status", port);
+	request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+		            "SCC-A RX", port);
+	request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+		            "SCC-A special cond", port);
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+		/* Set the interrupt vector */
+		SCCwrite(INT_VECTOR_REG, MVME162_IRQ_SCC_BASE);
+		/* Interrupt parameters: vector includes status, status low */
+		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+	}
+
+	/* Init channel B */
+	port = &scc_ports[1];
+	port->channel = CHANNEL_B;
+	port->ctrlp = (volatile unsigned char *)MVME_SCC_B_ADDR;
+	port->datap = port->ctrlp + 2;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+		            "SCC-B TX", port);
+	request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+		            "SCC-B status", port);
+	request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+		            "SCC-B RX", port);
+	request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+		            "SCC-B special cond", port);
+
+	{
+		SCC_ACCESS_INIT(port);	/* Either channel will do */
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+	}
+
+        /* Ensure interrupts are enabled in the MC2 chip */
+        *(volatile char *)0xfff4201d = 0x14;
+
+	/* Initialise the tty driver structures and register */
+	scc_init_portstructs();
+	scc_init_drivers();
+
+	return 0;
+}
+#endif
+
+
+#ifdef CONFIG_BVME6000_SCC
+static int bvme6000_scc_init(void)
+{
+	struct scc_port *port;
+
+	printk("SCC: BVME6000 Serial Driver\n");
+	/* Init channel A */
+	port = &scc_ports[0];
+	port->channel = CHANNEL_A;
+	port->ctrlp = (volatile unsigned char *)BVME_SCC_A_ADDR;
+	port->datap = port->ctrlp + 4;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+		            "SCC-A TX", port);
+	request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+		            "SCC-A status", port);
+	request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+		            "SCC-A RX", port);
+	request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+		            "SCC-A special cond", port);
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+		/* Set the interrupt vector */
+		SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE);
+		/* Interrupt parameters: vector includes status, status low */
+		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+	}
+
+	/* Init channel B */
+	port = &scc_ports[1];
+	port->channel = CHANNEL_B;
+	port->ctrlp = (volatile unsigned char *)BVME_SCC_B_ADDR;
+	port->datap = port->ctrlp + 4;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+		            "SCC-B TX", port);
+	request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+		            "SCC-B status", port);
+	request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+		            "SCC-B RX", port);
+	request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+		            "SCC-B special cond", port);
+
+	{
+		SCC_ACCESS_INIT(port);	/* Either channel will do */
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+	}
+
+	/* Initialise the tty driver structures and register */
+	scc_init_portstructs();
+	scc_init_drivers();
+
+	return 0;
+}
+#endif
+
+
+int vme_scc_init(void)
+{
+	int res = -ENODEV;
+	static int called = 0;
+
+	if (called)
+		return res;
+	called = 1;
+#ifdef CONFIG_MVME147_SCC
+	if (MACH_IS_MVME147)
+		res = mvme147_scc_init();
+#endif
+#ifdef CONFIG_MVME162_SCC
+	if (MACH_IS_MVME16x)
+		res = mvme162_scc_init();
+#endif
+#ifdef CONFIG_BVME6000_SCC
+	if (MACH_IS_BVME6000)
+		res = bvme6000_scc_init();
+#endif
+	return res;
+}
+
+
+/*---------------------------------------------------------------------------
+ * Interrupt handlers
+ *--------------------------------------------------------------------------*/
+
+static void scc_rx_int(int irq, void *data, struct pt_regs *fp)
+{
+	unsigned char	ch;
+	struct scc_port *port = data;
+	struct tty_struct *tty = port->gs.tty;
+	SCC_ACCESS_INIT(port);
+
+	ch = SCCread_NB(RX_DATA_REG);
+	if (!tty) {
+		printk ("scc_rx_int with NULL tty!\n");
+		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+		return;
+	}
+	if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = 0;
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	}
+
+	/* Check if another character is already ready; in that case, the
+	 * spcond_int() function must be used, because this character may have an
+	 * error condition that isn't signalled by the interrupt vector used!
+	 */
+	if (SCCread(INT_PENDING_REG) &
+	    (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
+		scc_spcond_int (irq, data, fp);
+		return;
+	}
+
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+
+	tty_flip_buffer_push(tty);
+}
+
+
+static void scc_spcond_int(int irq, void *data, struct pt_regs *fp)
+{
+	struct scc_port *port = data;
+	struct tty_struct *tty = port->gs.tty;
+	unsigned char	stat, ch, err;
+	int		int_pending_mask = port->channel == CHANNEL_A ?
+			                   IPR_A_RX : IPR_B_RX;
+	SCC_ACCESS_INIT(port);
+	
+	if (!tty) {
+		printk ("scc_spcond_int with NULL tty!\n");
+		SCCwrite(COMMAND_REG, CR_ERROR_RESET);
+		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+		return;
+	}
+	do {
+		stat = SCCread(SPCOND_STATUS_REG);
+		ch = SCCread_NB(RX_DATA_REG);
+
+		if (stat & SCSR_RX_OVERRUN)
+			err = TTY_OVERRUN;
+		else if (stat & SCSR_PARITY_ERR)
+			err = TTY_PARITY;
+		else if (stat & SCSR_CRC_FRAME_ERR)
+			err = TTY_FRAME;
+		else
+			err = 0;
+
+		if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+			*tty->flip.char_buf_ptr = ch;
+			*tty->flip.flag_buf_ptr = err;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+
+		/* ++TeSche: *All* errors have to be cleared manually,
+		 * else the condition persists for the next chars
+		 */
+		if (err)
+		  SCCwrite(COMMAND_REG, CR_ERROR_RESET);
+
+	} while(SCCread(INT_PENDING_REG) & int_pending_mask);
+
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+
+	tty_flip_buffer_push(tty);
+}
+
+
+static void scc_tx_int(int irq, void *data, struct pt_regs *fp)
+{
+	struct scc_port *port = data;
+	SCC_ACCESS_INIT(port);
+
+	if (!port->gs.tty) {
+		printk ("scc_tx_int with NULL tty!\n");
+		SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
+		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+		return;
+	}
+	while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) {
+		if (port->x_char) {
+			SCCwrite(TX_DATA_REG, port->x_char);
+			port->x_char = 0;
+		}
+		else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
+				port->gs.tty->hw_stopped)
+			break;
+		else {
+			SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]);
+			port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1);
+			if (--port->gs.xmit_cnt <= 0)
+				break;
+		}
+	}
+	if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
+			port->gs.tty->hw_stopped) {
+		/* disable tx interrupts */
+		SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);   /* disable tx_int on next tx underrun? */
+		port->gs.flags &= ~GS_TX_INTEN;
+	}
+	if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) {
+		if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+				port->gs.tty->ldisc.write_wakeup)
+			(port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+		wake_up_interruptible(&port->gs.tty->write_wait);
+	}
+
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+}
+
+
+static void scc_stat_int(int irq, void *data, struct pt_regs *fp)
+{
+	struct scc_port *port = data;
+	unsigned channel = port->channel;
+	unsigned char	last_sr, sr, changed;
+	SCC_ACCESS_INIT(port);
+
+	last_sr = scc_last_status_reg[channel];
+	sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG);
+	changed = last_sr ^ sr;
+
+	if (changed & SR_DCD) {
+		port->c_dcd = !!(sr & SR_DCD);
+		if (!(port->gs.flags & ASYNC_CHECK_CD))
+			;	/* Don't report DCD changes */
+		else if (port->c_dcd) {
+			if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) ||
+				~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) {
+				/* Are we blocking in open?*/
+				wake_up_interruptible(&port->gs.open_wait);
+			}
+		}
+		else {
+			if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
+					(port->gs.flags & ASYNC_CALLOUT_NOHUP))) {
+				if (port->gs.tty)
+					tty_hangup (port->gs.tty);
+			}
+		}
+	}
+	SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET);
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+}
+
+
+/*---------------------------------------------------------------------------
+ * generic_serial.c callback funtions
+ *--------------------------------------------------------------------------*/
+
+static void scc_disable_tx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	save_flags(flags);
+	cli();
+	SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+	port->gs.flags &= ~GS_TX_INTEN;
+	restore_flags(flags);
+}
+
+
+static void scc_enable_tx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	save_flags(flags);
+	cli();
+	SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
+	/* restart the transmitter */
+	scc_tx_int (0, port, 0);
+	restore_flags(flags);
+}
+
+
+static void scc_disable_rx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	save_flags(flags);
+	cli();
+	SCCmod(INT_AND_DMA_REG,
+	    ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0);
+	restore_flags(flags);
+}
+
+
+static void scc_enable_rx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	save_flags(flags);
+	cli();
+	SCCmod(INT_AND_DMA_REG, 0xff,
+		IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL);
+	restore_flags(flags);
+}
+
+
+static int scc_get_CD(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned channel = port->channel;
+
+	return !!(scc_last_status_reg[channel] & SR_DCD);
+}
+
+
+static void scc_shutdown_port(void *ptr)
+{
+	struct scc_port *port = ptr;
+
+	port->gs.flags &= ~ GS_ACTIVE;
+	if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
+		scc_setsignals (port, 0, 0);
+	}
+}
+
+
+static void scc_set_real_termios (void *ptr)
+{
+	/* the SCC has char sizes 5,7,6,8 in that order! */
+	static int chsize_map[4] = { 0, 2, 1, 3 };
+	unsigned cflag, baud, chsize, channel, brgval = 0;
+	unsigned long flags;
+	struct scc_port *port = ptr;
+	SCC_ACCESS_INIT(port);
+
+	if (!port->gs.tty || !port->gs.tty->termios) return;
+
+	channel = port->channel;
+
+	if (channel == CHANNEL_A)
+		return;		/* Settings controlled by boot PROM */
+
+	cflag  = port->gs.tty->termios->c_cflag;
+	baud = port->gs.baud;
+	chsize = (cflag & CSIZE) >> 4;
+
+	if (baud == 0) {
+		/* speed == 0 -> drop DTR */
+		save_flags(flags);
+		cli();
+		SCCmod(TX_CTRL_REG, ~TCR_DTR, 0);
+		restore_flags(flags);
+		return;
+	}
+	else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
+		 (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) ||
+		 (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) {
+		printk("SCC: Bad speed requested, %d\n", baud);
+		return;
+	}
+
+	if (cflag & CLOCAL)
+		port->gs.flags &= ~ASYNC_CHECK_CD;
+	else
+		port->gs.flags |= ASYNC_CHECK_CD;
+
+#ifdef CONFIG_MVME147_SCC
+	if (MACH_IS_MVME147)
+		brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
+	else
+#endif
+#ifdef CONFIG_MVME162_SCC
+	if (MACH_IS_MVME16x)
+		brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
+	else
+#endif
+#ifdef CONFIG_BVME6000_SCC
+	if (MACH_IS_BVME6000)
+		brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2;
+#endif
+	/* Now we have all parameters and can go to set them: */
+	save_flags(flags);
+	cli();
+
+	/* receiver's character size and auto-enables */
+	SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE),
+			(chsize_map[chsize] << 6) |
+			((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0));
+	/* parity and stop bits (both, Tx and Rx), clock mode never changes */
+	SCCmod (AUX1_CTRL_REG,
+		~(A1CR_PARITY_MASK | A1CR_MODE_MASK),
+		((cflag & PARENB
+		  ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN)
+		  : A1CR_PARITY_NONE)
+		 | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1)));
+	/* sender's character size, set DTR for valid baud rate */
+	SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR);
+	/* clock sources never change */
+	/* disable BRG before changing the value */
+	SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0);
+	/* BRG value */
+	SCCwrite(TIMER_LOW_REG, brgval & 0xff);
+	SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff);
+	/* BRG enable, and clock source never changes */
+	SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB);
+
+	restore_flags(flags);
+}
+
+
+static int scc_chars_in_buffer (void *ptr)
+{
+	struct scc_port *port = ptr;
+	SCC_ACCESS_INIT(port);
+
+	return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0  : 1;
+}
+
+
+static void scc_hungup(void *ptr)
+{
+	scc_disable_tx_interrupts(ptr);
+	scc_disable_rx_interrupts(ptr);
+	MOD_DEC_USE_COUNT;
+}
+
+
+static void scc_close(void *ptr)
+{
+	scc_disable_tx_interrupts(ptr);
+	scc_disable_rx_interrupts(ptr);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Internal support functions
+ *--------------------------------------------------------------------------*/
+
+static void scc_setsignals(struct scc_port *port, int dtr, int rts)
+{
+	unsigned long flags;
+	unsigned char t;
+	SCC_ACCESS_INIT(port);
+
+	save_flags(flags);
+	t = SCCread(TX_CTRL_REG);
+	if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR);
+	if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS);
+	SCCwrite(TX_CTRL_REG, t);
+	restore_flags(flags);
+}
+
+
+static void scc_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct scc_port *port = (struct scc_port *)tty->driver_data;
+
+	port->x_char = ch;
+	if (ch)
+		scc_enable_tx_interrupts(port);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Driver entrypoints referenced from above
+ *--------------------------------------------------------------------------*/
+
+static int scc_open (struct tty_struct * tty, struct file * filp)
+{
+	int line = MINOR(tty->device) - SCC_MINOR_BASE;
+	int retval;
+	struct scc_port *port = &scc_ports[line];
+	int i, channel = port->channel;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC)
+	static const struct {
+		unsigned reg, val;
+	} mvme_init_tab[] = {
+		/* Values for MVME162 and MVME147 */
+		/* no parity, 1 stop bit, async, 1:16 */
+		{ AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
+		/* parity error is special cond, ints disabled, no DMA */
+		{ INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
+		/* Rx 8 bits/char, no auto enable, Rx off */
+		{ RX_CTRL_REG, RCR_CHSIZE_8 },
+		/* DTR off, Tx 8 bits/char, RTS off, Tx off */
+		{ TX_CTRL_REG, TCR_CHSIZE_8 },
+		/* special features off */
+		{ AUX2_CTRL_REG, 0 },
+		{ CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG },
+		{ DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK },
+		/* Start Rx */
+		{ RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
+		/* Start Tx */
+		{ TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
+		/* Ext/Stat ints: DCD only */
+		{ INT_CTRL_REG, ICR_ENAB_DCD_INT },
+		/* Reset Ext/Stat ints */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+		/* ...again */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+	};
+#endif
+#if defined(CONFIG_BVME6000_SCC)
+	static const struct {
+		unsigned reg, val;
+	} bvme_init_tab[] = {
+		/* Values for BVME6000 */
+		/* no parity, 1 stop bit, async, 1:16 */
+		{ AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
+		/* parity error is special cond, ints disabled, no DMA */
+		{ INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
+		/* Rx 8 bits/char, no auto enable, Rx off */
+		{ RX_CTRL_REG, RCR_CHSIZE_8 },
+		/* DTR off, Tx 8 bits/char, RTS off, Tx off */
+		{ TX_CTRL_REG, TCR_CHSIZE_8 },
+		/* special features off */
+		{ AUX2_CTRL_REG, 0 },
+		{ CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG },
+		{ DPLL_CTRL_REG, DCR_BRG_ENAB },
+		/* Start Rx */
+		{ RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
+		/* Start Tx */
+		{ TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
+		/* Ext/Stat ints: DCD only */
+		{ INT_CTRL_REG, ICR_ENAB_DCD_INT },
+		/* Reset Ext/Stat ints */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+		/* ...again */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+	};
+#endif
+	if (!(port->gs.flags & ASYNC_INITIALIZED)) {
+		save_flags(flags);
+		cli();
+#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC)
+		if (MACH_IS_MVME147 || MACH_IS_MVME16x) {
+			for (i=0; i<sizeof(mvme_init_tab)/sizeof(*mvme_init_tab); ++i)
+				SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val);
+		}
+#endif
+#if defined(CONFIG_BVME6000_SCC)
+		if (MACH_IS_BVME6000) {
+			for (i=0; i<sizeof(bvme_init_tab)/sizeof(*bvme_init_tab); ++i)
+				SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val);
+		}
+#endif
+
+		/* remember status register for detection of DCD and CTS changes */
+		scc_last_status_reg[channel] = SCCread(STATUS_REG);
+
+		port->c_dcd = 0;	/* Prevent initial 1->0 interrupt */
+		scc_setsignals (port, 1,1);
+		restore_flags(flags);
+	}
+
+	tty->driver_data = port;
+	port->gs.tty = tty;
+	port->gs.count++;
+	retval = gs_init_port(&port->gs);
+	if (retval) {
+		port->gs.count--;
+		return retval;
+	}
+	port->gs.flags |= GS_ACTIVE;
+	if (port->gs.count == 1) {
+		MOD_INC_USE_COUNT;
+	}
+	retval = block_til_ready(port, filp);
+
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		port->gs.count--;
+		return retval;
+	}
+
+	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = port->gs.normal_termios;
+		else 
+			*tty->termios = port->gs.callout_termios;
+		scc_set_real_termios (port);
+	}
+
+	port->gs.session = current->session;
+	port->gs.pgrp = current->pgrp;
+	port->c_dcd = scc_get_CD (port);
+
+	scc_enable_rx_interrupts(port);
+
+	return 0;
+}
+
+
+static void scc_throttle (struct tty_struct * tty)
+{
+	struct scc_port *port = (struct scc_port *)tty->driver_data;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	if (tty->termios->c_cflag & CRTSCTS) {
+		save_flags(flags);
+		cli();
+		SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
+		restore_flags(flags);
+	}
+	if (I_IXOFF(tty))
+		scc_send_xchar(tty, STOP_CHAR(tty));
+}
+
+
+static void scc_unthrottle (struct tty_struct * tty)
+{
+	struct scc_port *port = (struct scc_port *)tty->driver_data;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	if (tty->termios->c_cflag & CRTSCTS) {
+		save_flags(flags);
+		cli();
+		SCCmod(TX_CTRL_REG, 0xff, TCR_RTS);
+		restore_flags(flags);
+	}
+	if (I_IXOFF(tty))
+		scc_send_xchar(tty, START_CHAR(tty));
+}
+
+
+static int scc_ioctl(struct tty_struct *tty, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+
+static void scc_break_ctl(struct tty_struct *tty, int break_state)
+{
+	struct scc_port *port = (struct scc_port *)tty->driver_data;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	save_flags(flags);
+	cli();
+	SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, 
+			break_state ? TCR_SEND_BREAK : 0);
+	restore_flags(flags);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Serial console stuff...
+ *--------------------------------------------------------------------------*/
+
+#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0)
+
+static void scc_ch_write (char ch)
+{
+	volatile char *p = NULL;
+	
+#ifdef CONFIG_MVME147_SCC
+	if (MACH_IS_MVME147)
+		p = (volatile char *)M147_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_MVME162_SCC
+	if (MACH_IS_MVME16x)
+		p = (volatile char *)MVME_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_BVME6000_SCC
+	if (MACH_IS_BVME6000)
+		p = (volatile char *)BVME_SCC_A_ADDR;
+#endif
+
+	do {
+		scc_delay();
+	}
+	while (!(*p & 4));
+	scc_delay();
+	*p = 8;
+	scc_delay();
+	*p = ch;
+}
+
+
+static void scc_console_write (struct console *co, const char *str, unsigned count)
+{
+	unsigned long	flags;
+
+	save_flags(flags);
+	cli();
+
+	while (count--)
+	{
+		if (*str == '\n')
+			scc_ch_write ('\r');
+		scc_ch_write (*str++);
+	}
+	restore_flags(flags);
+}
+
+
+static int scc_console_wait_key(struct console *co)
+{
+	unsigned long	flags;
+	volatile char *p = NULL;
+	int c;
+	
+#ifdef CONFIG_MVME147_SCC
+	if (MACH_IS_MVME147)
+		p = (volatile char *)M147_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_MVME162_SCC
+	if (MACH_IS_MVME16x)
+		p = (volatile char *)MVME_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_BVME6000_SCC
+	if (MACH_IS_BVME6000)
+		p = (volatile char *)BVME_SCC_A_ADDR;
+#endif
+
+	save_flags(flags);
+	cli();
+
+	/* wait for rx buf filled */
+	while ((*p & 0x01) == 0)
+		;
+
+	*p = 8;
+	scc_delay();
+	c = *p;
+	restore_flags(flags);
+	return c;
+}
+
+
+static kdev_t scc_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, SCC_MINOR_BASE + c->index);
+}
+
+
+static int __init scc_console_setup(struct console *co, char *options)
+{
+	return 0;
+}
+
+
+static struct console sercons = {
+	"ttyS",
+	scc_console_write,
+	NULL,
+	scc_console_device,
+	scc_console_wait_key,
+	NULL,
+	scc_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+
+void __init vme_scc_console_init(void)
+{
+	if (vme_brdtype == VME_TYPE_MVME147 ||
+			vme_brdtype == VME_TYPE_MVME162 ||
+			vme_brdtype == VME_TYPE_MVME172 ||
+			vme_brdtype == VME_TYPE_BVME4000 ||
+			vme_brdtype == VME_TYPE_BVME6000)
+		register_console(&sercons);
+}
+
diff -u --recursive --new-file v2.3.41/linux/drivers/i2c/Config.in linux/drivers/i2c/Config.in
--- v2.3.41/linux/drivers/i2c/Config.in	Mon Dec 20 18:48:21 1999
+++ linux/drivers/i2c/Config.in	Fri Jan 28 19:36:23 2000
@@ -8,22 +8,22 @@
 
 if [ "$CONFIG_I2C" != "n" ]; then
 
-  dep_tristate 'I2C bit-banging interfaces'  CONFIG_I2C_ALGOBIT $CONFIG_I2C
-  if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then
-    dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT
-    dep_tristate '  ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
-    dep_tristate '  Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
-  fi
+   dep_tristate 'I2C bit-banging interfaces'  CONFIG_I2C_ALGOBIT $CONFIG_I2C
+   if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then
+      dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT
+      dep_tristate '  ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
+      dep_tristate '  Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+   fi
 
-  dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
-  if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then
-    dep_tristate '  Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF
-  fi
+   dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
+   if [ "$CONFIG_I2C_ALGOPCF" != "n" ]; then
+      dep_tristate '  Elektor ISA card' CONFIG_I2C_ELEKTOR $CONFIG_I2C_ALGOPCF
+   fi
 
 # This is needed for automatic patch generation: sensors code starts here
 # This is needed for automatic patch generation: sensors code ends here
 
-  dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
+   dep_tristate 'I2C device interface' CONFIG_I2C_CHARDEV $CONFIG_I2C
 
 fi
 endmenu
diff -u --recursive --new-file v2.3.41/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c
--- v2.3.41/linux/drivers/i2c/i2c-core.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/i2c/i2c-core.c	Fri Jan 28 19:36:23 2000
@@ -20,7 +20,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
    All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-core.c,v 1.44 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-core.c,v 1.48 2000/01/24 21:41:19 frodo Exp $ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -33,37 +33,14 @@
 
 /* ----- compatibility stuff ----------------------------------------------- */
 
-/* 2.0.0 kernel compatibility */
-#if LINUX_VERSION_CODE < 0x020100
-#define MODULE_AUTHOR(noone)
-#define MODULE_DESCRIPTION(none)
-#define MODULE_PARM(no,param)
-#define MODULE_PARM_DESC(no,description)
-#define EXPORT_SYMBOL(noexport)
-#define EXPORT_NO_SYMBOLS
-#endif
-
 #include <linux/version.h>
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53)
 #include <linux/init.h>
-#else
-#define __init 
-#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
 #define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
 #endif
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4))
-#define copy_from_user memcpy_fromfs
-#define copy_to_user memcpy_tofs
-#else
 #include <asm/uaccess.h>
-#endif
 
 /* ----- global defines ---------------------------------------------------- */
 
@@ -83,8 +60,8 @@
 /* ----- global variables -------------------------------------------------- */
 
 /**** lock for writing to global variables: the adapter & driver list */
-struct semaphore adap_lock;  
-struct semaphore driver_lock;  
+struct semaphore adap_lock;
+struct semaphore driver_lock;
 
 /**** adapter list */
 static struct i2c_adapter *adapters[I2C_ADAP_MAX];
@@ -104,73 +81,29 @@
  *----------------------------------------------------
  */
 
-/* Note that quite some things changed within the 2.1 kernel series.
-   Some things below are somewhat difficult to read because of this. */
-
 #ifdef CONFIG_PROC_FS
 
 static int i2cproc_init(void);
 static int i2cproc_cleanup(void);
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
-    (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
 static void monitor_bus_i2c(struct inode *inode, int fill);
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
-
 static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
                                 loff_t *ppos);
 static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
                            int *eof , void *private);
 
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-
-static int i2cproc_bus_read(struct inode * inode, struct file * file,
-                            char * buf, int count);
-static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
-                        int unused);
-
-static struct proc_dir_entry proc_bus_dir =
-  {
-    /* low_ino */       0,     /* Set by proc_register_dynamic */
-    /* namelen */       3, 
-    /* name */          "bus",
-    /* mode */          S_IRUGO | S_IXUGO | S_IFDIR,
-    /* nlink */         2,     /* Corrected by proc_register[_dynamic] */
-    /* uid */           0,
-    /* gid */           0,
-    /* size */          0,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36))
-    /* ops */           &proc_dir_inode_operations, 
-#endif
-  };
-
-static struct proc_dir_entry proc_bus_i2c_dir =
-  {
-    /* low_ino */       0,     /* Set by proc_register_dynamic */
-    /* namelen */       3, 
-    /* name */          "i2c",
-    /* mode */          S_IRUGO | S_IFREG,
-    /* nlink */         1,     
-    /* uid */           0,
-    /* gid */           0,
-    /* size */          0,
-    /* ops */           NULL,
-    /* get_info */      &read_bus_i2c
-  };
-
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
-
 /* To implement the dynamic /proc/bus/i2c-? files, we need our own 
    implementation of the read hook */
 static struct file_operations i2cproc_operations = {
-        NULL,
-        i2cproc_bus_read,
+	NULL,
+	i2cproc_bus_read,
 };
 
 static struct inode_operations i2cproc_inode_operations = {
-        &i2cproc_operations
+	&i2cproc_operations
 };
 
 static int i2cproc_initialized = 0;
@@ -183,7 +116,7 @@
 #endif /* CONFIG_PROC_FS */
 
 
-/* ---------------------------------------------------    
+/* ---------------------------------------------------
  * registering functions 
  * --------------------------------------------------- 
  */
@@ -222,55 +155,21 @@
 	if (i2cproc_initialized) {
 		char name[8];
 		struct proc_dir_entry *proc_entry;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
-		int res;
-#endif
 
 		sprintf(name,"i2c-%d", i);
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
 		proc_entry = create_proc_entry(name,0,proc_bus);
 		if (! proc_entry) {
 			printk("i2c-core.o: Could not create /proc/bus/%s\n",
-                               name);
+			       name);
 			return -ENOENT;
-  		}
+		}
 		proc_entry->ops = &i2cproc_inode_operations;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
 		proc_entry->owner = THIS_MODULE;
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+#else
 		proc_entry->fill_inode = &monitor_bus_i2c;
 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-		adap->proc_entry = NULL;
-		if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+
-                                           strlen(name)+1, GFP_KERNEL))) {
-			printk("i2c-core.o: Out of memory!\n");
-			return -ENOMEM;
-		}
-		memset(proc_entry,0,sizeof(struct proc_dir_entry));
-		proc_entry->namelen = strlen(name);
-		proc_entry->name = (char *) (proc_entry + 1);
-		proc_entry->mode = S_IRUGO | S_IFREG;
-		proc_entry->nlink = 1;
-		proc_entry->ops = &i2cproc_inode_operations;
-	
-		/* Nasty stuff to keep GCC satisfied */
-		{ 
-			char *procname;
-			(const char *) procname  = proc_entry->name;
-			strcpy (procname,name);
-		}
-	
-		if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) {
-			printk("i2c-core.o: Could not create %s.\n",name);
-			kfree(proc_entry);
-			return res;
-		}
-	
-		adap->proc_entry = proc_entry;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
-
 		adap->inode = proc_entry->low_ino;
 	}
 
@@ -283,7 +182,8 @@
 			drivers[j]->attach_adapter(adap);
 	DRV_UNLOCK();
 	
-	DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",adap->name,i));
+	DEB(printk("i2c-core.o: adapter %s registered as adapter %d.\n",
+	           adap->name,i));
 
 	return 0;	
 }
@@ -306,23 +206,9 @@
 	i2c_dummy_adapter(adap);  /* actually i2c_dummy->del_adapter */
 #ifdef CONFIG_PROC_FS
 	if (i2cproc_initialized) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
 		char name[8];
 		sprintf(name,"i2c-%d", i);
 		remove_proc_entry(name,proc_bus);
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-		int res;
-		if (adapters[i]->proc_entry) {
-			if ((res = proc_unregister(&proc_bus_dir,
-			                  adapters[i]->proc_entry->low_ino))) {
-				printk("i2c-core.o: Deregistration of /proc "
-				       "entry failed\n");
-				ADAP_UNLOCK();
-				return res;
-			}
-			kfree(adapters[i]->proc_entry);
-		}
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
 	}
 #endif /* def CONFIG_PROC_FS */
 
@@ -344,7 +230,7 @@
 	
 	ADAP_UNLOCK();	
 	DEB(printk("i2c-core.o: adapter unregistered: %s\n",adap->name));
-	return 0;    
+	return 0;
 }
 
 
@@ -384,7 +270,8 @@
 				driver->attach_adapter(adapters[i]);
 		 		for (j=0; j<I2C_CLIENT_MAX; j++)
 		 			if (adapters[i]->clients[j])
-	 				driver->detach_client(adapters[i]->clients[j]);
+	 				driver->detach_client(
+					             adapters[i]->clients[j]);
 			}
 		}
 		ADAP_UNLOCK();
@@ -418,7 +305,7 @@
 	}
 	/* Have a look at each adapter, if clients of this driver are still
 	 * attached. If so, detach them to be able to kill the driver 
-         * afterwards.
+	 * afterwards.
 	 */
 	DEB2(printk("i2c-core.o: unregister_driver - looking for clients.\n"));
 	/* removing clients does not depend on the notify flag, else 
@@ -453,11 +340,11 @@
 
 int i2c_check_addr (struct i2c_adapter *adapter, int addr)
 {
-  int i;
-  for (i = 0; i < I2C_CLIENT_MAX ; i++) 
-    if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
-      return -EBUSY;
-  return 0;
+	int i;
+	for (i = 0; i < I2C_CLIENT_MAX ; i++) 
+		if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+			return -EBUSY;
+	return 0;
 }
 
 int i2c_attach_client(struct i2c_client *client)
@@ -465,8 +352,8 @@
 	struct i2c_adapter *adapter = client->adapter;
 	int i;
 
-        if (i2c_check_addr(client->adapter,client->addr))
-          return -EBUSY;
+	if (i2c_check_addr(client->adapter,client->addr))
+		return -EBUSY;
 
 	for (i = 0; i < I2C_CLIENT_MAX; i++)
 		if (NULL == adapter->clients[i])
@@ -513,7 +400,7 @@
 	i2c_dummy_client(client);
 
 	DEB(printk("i2c-core.o: client [%s] unregistered.\n",client->name));
-	return 0;    
+	return 0;
 }
 
 void i2c_inc_use_client(struct i2c_client *client)
@@ -543,26 +430,21 @@
 
 #ifdef CONFIG_PROC_FS
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) && \
-    (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,27))
 /* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible
    if some process still uses it or some file in it */
 void monitor_bus_i2c(struct inode *inode, int fill)
 {
-  if (fill)
-    MOD_INC_USE_COUNT;
-  else
-    MOD_DEC_USE_COUNT;
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
 }
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
+#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,37)) */
 
 /* This function generates the output for /proc/bus/i2c */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
 int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, 
                  void *private)
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
 {
 	int i;
 	int nr = 0;
@@ -571,7 +453,7 @@
 		if (adapters[i]) {
 			nr += sprintf(buf+nr, "i2c-%d\t", i);
 			if (adapters[i]->algo->smbus_xfer) {
-			        if (adapters[i]->algo->master_xfer)
+				if (adapters[i]->algo->master_xfer)
 					nr += sprintf(buf+nr,"smbus/i2c");
 				else
 					nr += sprintf(buf+nr,"smbus    ");
@@ -587,62 +469,55 @@
 }
 
 /* This function generates the output for /proc/bus/i2c-? */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
 ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
                          loff_t *ppos)
 {
-  struct inode * inode = file->f_dentry->d_inode;
-#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
-int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf,
-                     int count)
-{
-#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
-  char *kbuf;
-  struct i2c_client *client;
-  int i,j,len=0;
-
-  if (count < 0)
-    return -EINVAL;
-  if (count > 4000)
-    count = 4000;
-  for (i = 0; i < I2C_ADAP_MAX; i++)
-    if (adapters[i]->inode == inode->i_ino) {
-      /* We need a bit of slack in the kernel buffer; this makes the
-         sprintf safe. */
-      if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
-        return -ENOMEM;
-      for (j = 0; j < I2C_CLIENT_MAX; j++)
-        if ((client = adapters[i]->clients[j]))
-          /* Filter out dummy clients */
-          if (client->driver->id != I2C_DRIVERID_I2CDEV)
-            len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
-                           client->addr,
-                           client->name,client->driver->name);
-      if (file->f_pos+len > count)
-        len = count - file->f_pos;
-      len = len - file->f_pos;
-      if (len < 0) 
-        len = 0;
-      copy_to_user (buf,kbuf+file->f_pos,len);
-      file->f_pos += len;
-      kfree(kbuf);
-      return len;
-    }
-  return -ENOENT;
+	struct inode * inode = file->f_dentry->d_inode;
+	char *kbuf;
+	struct i2c_client *client;
+	int i,j,len=0;
+
+	if (count < 0)
+		return -EINVAL;
+	if (count > 4000)
+		count = 4000;
+	for (i = 0; i < I2C_ADAP_MAX; i++)
+		if (adapters[i]->inode == inode->i_ino) {
+		/* We need a bit of slack in the kernel buffer; this makes the
+		   sprintf safe. */
+			if (! (kbuf = kmalloc(count + 80,GFP_KERNEL)))
+				return -ENOMEM;
+			for (j = 0; j < I2C_CLIENT_MAX; j++)
+				if ((client = adapters[i]->clients[j]))
+					/* Filter out dummy clients */
+					if (client->driver->id != I2C_DRIVERID_I2CDEV)
+						len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n",
+						              client->addr,
+						              client->name,client->driver->name);
+					if (file->f_pos+len > count)
+						len = count - file->f_pos;
+					len = len - file->f_pos;
+					if (len < 0) 
+						len = 0;
+					if (copy_to_user (buf,kbuf+file->f_pos,
+					    len)) {
+						kfree(kbuf);
+						return -EFAULT;
+					}
+					file->f_pos += len;
+					kfree(kbuf);
+					return len;
+		}
+	return -ENOENT;
 }
 
 int i2cproc_init(void)
 {
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
 	struct proc_dir_entry *proc_bus_i2c;
-#else
-	int res;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
 
 	i2cproc_initialized = 0;
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
 	if (! proc_bus) {
 		printk("i2c-core.o: /proc/bus/ does not exist");
 		i2cproc_cleanup();
@@ -657,29 +532,10 @@
 	proc_bus_i2c->read_proc = &read_bus_i2c;
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
 	proc_bus_i2c->owner = THIS_MODULE;
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
+#else
 	proc_bus_i2c->fill_inode = &monitor_bus_i2c;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */
 	i2cproc_initialized += 2;
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-	/* In Linux 2.0.x, there is no /proc/bus! But I hope no other module
-	   introduced it, or we are fucked. And 2.0.35 and earlier does not
-	   export proc_dir_inode_operations, so we grab it from proc_net,
-	   which also uses it. Not nice. */
-	proc_bus_dir.ops = proc_net.ops;
-	if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) {
-		printk("i2c-core.o: Could not create /proc/bus/");
-		i2cproc_cleanup();
-		return res;
-	}
-	i2cproc_initialized ++;
-	if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) {
-		printk("i2c-core.o: Could not create /proc/bus/i2c\n");
-		i2cproc_cleanup();
-		return res;
-	}
-	i2cproc_initialized ++;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
 	return 0;
 }
 
@@ -687,27 +543,8 @@
 {
 
 	if (i2cproc_initialized >= 1) {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
 		remove_proc_entry("i2c",proc_bus);
 		i2cproc_initialized -= 2;
-#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
-		int res;
-		if (i2cproc_initialized >= 2) {
-			if ((res = proc_unregister(&proc_bus_dir,
-			                          proc_bus_i2c_dir.low_ino))) {
-				printk("i2c-core.o: could not delete "
-				       "/proc/bus/i2c, module not removed.");
-				return res;
-			}    
-			i2cproc_initialized --;
-		}
-		if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) {
-			printk("i2c-core.o: could not delete /proc/bus/, "
-			       "module not removed.");
-			return res;
-		}    
-		i2cproc_initialized --;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
 	}
 	return 0;
 }
@@ -715,7 +552,7 @@
 
 #endif /* def CONFIG_PROC_FS */
 
-/* ---------------------------------------------------    
+/* ---------------------------------------------------
  * dummy driver notification
  * --------------------------------------------------- 
  */
@@ -724,16 +561,16 @@
 {
 	int i;	
 	for (i=0; i<I2C_DRIVER_MAX; i++)
-	  if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
-	    drivers[i]->attach_adapter(adap);
+		if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+		    drivers[i]->attach_adapter(adap);
 }
 
 static void i2c_dummy_client(struct i2c_client *client)
 {
 	int i;
 	for (i=0; i<I2C_DRIVER_MAX; i++)
-	  if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
-	    drivers[i]->detach_client(client);
+		if (drivers[i] && (drivers[i]->flags & I2C_DF_DUMMY))
+		    drivers[i]->detach_client(client);
 }
 
 
@@ -747,7 +584,8 @@
 	int ret;
 
 	if (adap->algo->master_xfer) {
- 	 	DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",adap->name,num));
+ 	 	DEB2(printk("i2c-core.o: master_xfer: %s with %d msgs.\n",
+		            adap->name,num));
 
 		I2C_LOCK(adap);
 		ret = adap->algo->master_xfer(adap,msgs,num);
@@ -756,7 +594,7 @@
 		return ret;
 	} else {
 		printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
-                       adap->id);
+		       adap->id);
 		return -ENOSYS;
 	}
 }
@@ -786,7 +624,7 @@
 		return (ret == 1 )? count : ret;
 	} else {
 		printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
-                       client->adapter->id);
+		       client->adapter->id);
 		return -ENOSYS;
 	}
 }
@@ -819,7 +657,7 @@
 		return (ret == 1 )? count : ret;
 	} else {
 		printk("i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n",
-                       client->adapter->id);
+		       client->adapter->id);
 		return -ENOSYS;
 	}
 }
@@ -855,128 +693,124 @@
                    struct i2c_client_address_data *address_data,
                    i2c_client_found_addr_proc *found_proc)
 {
-  int addr,i,found,err;
-  int adap_id = i2c_adapter_id(adapter);
+	int addr,i,found,err;
+	int adap_id = i2c_adapter_id(adapter);
+
+	/* Forget it if we can't probe using SMBUS_QUICK */
+	if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
+		return -1;
+
+	for (addr = 0x00; addr <= 0x7f; addr++) {
+
+		/* Skip if already in use */
+		if (i2c_check_addr(adapter,addr))
+			continue;
+
+		/* If it is in one of the force entries, we don't do any detection
+		   at all */
+		found = 0;
+
+		for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) {
+			if (((adap_id == address_data->force[i]) || 
+			     (address_data->force[i] == ANY_I2C_BUS)) &&
+			     (addr == address_data->force[i+1])) {
+				DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n",
+				            adap_id,addr));
+				if ((err = found_proc(adapter,addr,0,0)))
+					return err;
+				found = 1;
+			}
+		}
+		if (found) 
+			continue;
+
+		/* If this address is in one of the ignores, we can forget about
+		   it right now */
+		for (i = 0;
+		     !found && (address_data->ignore[i] != I2C_CLIENT_END);
+		     i += 2) {
+			if (((adap_id == address_data->ignore[i]) || 
+			    ((address_data->ignore[i] == ANY_I2C_BUS))) &&
+			    (addr == address_data->ignore[i+1])) {
+				DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, "
+				     "addr %04x\n", adap_id ,addr));
+				found = 1;
+			}
+		}
+		for (i = 0;
+		     !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
+		     i += 3) {
+			if (((adap_id == address_data->ignore_range[i]) ||
+			    ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
+			    (addr >= address_data->ignore_range[i+1]) &&
+			    (addr <= address_data->ignore_range[i+2])) {
+				DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, "
+				            "addr %04x\n", adap_id,addr));
+				found = 1;
+			}
+		}
+		if (found) 
+			continue;
+
+		/* Now, we will do a detection, but only if it is in the normal or 
+		   probe entries */  
+		for (i = 0;
+		     !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
+		     i += 1) {
+			if (addr == address_data->normal_i2c[i]) {
+				found = 1;
+				DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, "
+				            "addr %02x", adap_id,addr));
+			}
+		}
+
+		for (i = 0;
+		     !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
+		     i += 2) {
+			if ((addr >= address_data->normal_i2c_range[i]) &&
+			    (addr <= address_data->normal_i2c_range[i+1])) {
+				found = 1;
+				DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, "
+				            "addr %04x\n", adap_id,addr));
+			}
+		}
+
+		for (i = 0;
+		     !found && (address_data->probe[i] != I2C_CLIENT_END);
+		     i += 2) {
+			if (((adap_id == address_data->probe[i]) ||
+			    ((address_data->probe[i] == ANY_I2C_BUS))) &&
+			    (addr == address_data->probe[i+1])) {
+				found = 1;
+				DEB2(printk("i2c-core.o: found probe parameter for adapter %d, "
+				            "addr %04x\n", adap_id,addr));
+			}
+		}
+		for (i = 0;
+		     !found && (address_data->probe_range[i] != I2C_CLIENT_END);
+		     i += 3) {
+			if (((adap_id == address_data->probe_range[i]) ||
+			   (address_data->probe_range[i] == ANY_I2C_BUS)) &&
+			   (addr >= address_data->probe_range[i+1]) &&
+			   (addr <= address_data->probe_range[i+2])) {
+				found = 1;
+				DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, "
+				            "addr %04x\n", adap_id,addr));
+			}
+		}
+		if (!found) 
+			continue;
 
-  /* Forget it if we can't probe using SMBUS_QUICK */
-  if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK))
-    return -1;
-
-  for (addr = 0x00; 
-       addr <= 0x7f;
-       addr++) {
-
-    /* Skip if already in use */
-    if (i2c_check_addr(adapter,addr))
-      continue;
-
-    /* If it is in one of the force entries, we don't do any detection
-       at all */
-    found = 0;
-
-    for (i = 0;
-         !found && (address_data->force[i] != I2C_CLIENT_END);
-         i += 3) {
-      if (((adap_id == address_data->force[i]) || 
-           (address_data->force[i] == ANY_I2C_BUS)) &&
-           (addr == address_data->force[i+1])) {
-	DEB2(printk("i2c-core.o: found force parameter for adapter %d, addr %04x\n",
-               adap_id,addr));
-        if ((err = found_proc(adapter,addr,0,0)))
-           return err;
-        found = 1;
-      }
-    }
-    if (found) 
-      continue;
-
-    /* If this address is in one of the ignores, we can forget about it
-       right now */
-    for (i = 0;
-         !found && (address_data->ignore[i] != I2C_CLIENT_END); 
-         i += 2) {
-      if (((adap_id == address_data->ignore[i]) || 
-           ((address_data->ignore[i] == ANY_I2C_BUS))) &&
-          (addr == address_data->ignore[i+1])) {
-          DEB2(printk("i2c-core.o: found ignore parameter for adapter %d, "
-                 "addr %04x\n", adap_id ,addr));
-        found = 1;
-      }
-    }
-    for (i = 0;
-         !found && (address_data->ignore_range[i] != I2C_CLIENT_END);
-         i += 3) {
-      if (((adap_id == address_data->ignore_range[i]) ||
-           ((address_data->ignore_range[i]==ANY_I2C_BUS))) &&
-          (addr >= address_data->ignore_range[i+1]) &&
-          (addr <= address_data->ignore_range[i+2])) {
-        DEB2(printk("i2c-core.o: found ignore_range parameter for adapter %d, "
-                 "addr %04x\n", adap_id,addr));
-        found = 1;
-      }
-    }
-    if (found) 
-      continue;
-
-    /* Now, we will do a detection, but only if it is in the normal or 
-       probe entries */  
-    for (i = 0;
-         !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
-         i += 1) {
-      if (addr == address_data->normal_i2c[i]) {
-        found = 1;
-        DEB2(printk("i2c-core.o: found normal i2c entry for adapter %d, "
-               "addr %02x", adap_id,addr));
-        }
-    }
-
-    for (i = 0;
-         !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END);
-         i += 2) {
-      if ((addr >= address_data->normal_i2c_range[i]) &&
-          (addr <= address_data->normal_i2c_range[i+1])) {
-        found = 1;
-        DEB2(printk("i2c-core.o: found normal i2c_range entry for adapter %d, "
-               "addr %04x\n", adap_id,addr));
-      }
-    }
-
-    for (i = 0;
-         !found && (address_data->probe[i] != I2C_CLIENT_END);
-         i += 2) {
-      if (((adap_id == address_data->probe[i]) ||
-           ((address_data->probe[i] == ANY_I2C_BUS))) &&
-          (addr == address_data->probe[i+1])) {
-        found = 1;
-	DEB2(printk("i2c-core.o: found probe parameter for adapter %d, "
-                 "addr %04x\n", adap_id,addr));
-      }
-    }
-    for (i = 0;
-         !found && (address_data->probe_range[i] != I2C_CLIENT_END);
-         i += 3) {
-      if (((adap_id == address_data->probe_range[i]) ||
-           (address_data->probe_range[i] == ANY_I2C_BUS)) &&
-          (addr >= address_data->probe_range[i+1]) &&
-          (addr <= address_data->probe_range[i+2])) {
-        found = 1;
-	DEB2(printk("i2c-core.o: found probe_range parameter for adapter %d, "
-                 "addr %04x\n", adap_id,addr));
-      }
-    }
-    if (!found) 
-      continue;
-
-    /* OK, so we really should examine this address. First check
-       whether there is some client here at all! */
-    if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
-      if ((err = found_proc(adapter,addr,0,-1)))
-        return err;
-  }
-  return 0;
+		/* OK, so we really should examine this address. First check
+		   whether there is some client here at all! */
+		if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0)
+			if ((err = found_proc(adapter,addr,0,-1)))
+				return err;
+	}
+	return 0;
 }
 
-/* +++ frodo
+/*
  * return id number for a specific adapter
  */
 int i2c_adapter_id(struct i2c_adapter *adap)
@@ -993,14 +827,14 @@
 extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value)
 {
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                              value,0,I2C_SMBUS_QUICK,NULL);
+ 	                      value,0,I2C_SMBUS_QUICK,NULL);
 }
 
 extern s32 i2c_smbus_read_byte(struct i2c_client * client)
 {
 	union i2c_smbus_data data;
 	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                           I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
+	                   I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
 		return -1;
 	else
 		return 0x0FF & data.byte;
@@ -1009,26 +843,26 @@
 extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value)
 {
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                              I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+	                      I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
 }
 
 extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command)
 {
 	union i2c_smbus_data data;
 	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                           I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
+	                   I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
 		return -1;
 	else
 		return 0x0FF & data.byte;
 }
 
-extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, 
-                                     u8 command, u8 value)
+extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, u8 command,
+                                     u8 value)
 {
 	union i2c_smbus_data data;
 	data.byte = value;
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                              I2C_SMBUS_WRITE,command,
+	                      I2C_SMBUS_WRITE,command,
 	                      I2C_SMBUS_BYTE_DATA,&data);
 }
 
@@ -1036,7 +870,7 @@
 {
 	union i2c_smbus_data data;
 	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                           I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
+	                   I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
 		return -1;
 	else
 		return 0x0FFFF & data.word;
@@ -1048,8 +882,8 @@
 	union i2c_smbus_data data;
 	data.word = value;
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                              I2C_SMBUS_WRITE,command,
-                              I2C_SMBUS_WORD_DATA,&data);
+	                      I2C_SMBUS_WRITE,command,
+	                      I2C_SMBUS_WORD_DATA,&data);
 }
 
 extern s32 i2c_smbus_process_call(struct i2c_client * client,
@@ -1058,8 +892,8 @@
 	union i2c_smbus_data data;
 	data.word = value;
 	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                           I2C_SMBUS_WRITE,command,
-                           I2C_SMBUS_PROC_CALL, &data))
+	                   I2C_SMBUS_WRITE,command,
+	                   I2C_SMBUS_PROC_CALL, &data))
 		return -1;
 	else
 		return 0x0FFFF & data.word;
@@ -1072,7 +906,7 @@
 	union i2c_smbus_data data;
 	int i;
 	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                           I2C_SMBUS_READ,command,
+	                   I2C_SMBUS_READ,command,
 	                   I2C_SMBUS_BLOCK_DATA,&data))
 		return -1;
 	else {
@@ -1093,7 +927,7 @@
 		data.block[i] = values[i-1];
 	data.block[0] = length;
 	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                              I2C_SMBUS_WRITE,command,
+	                      I2C_SMBUS_WRITE,command,
 	                      I2C_SMBUS_BLOCK_DATA,&data);
 }
 
@@ -1177,7 +1011,7 @@
 		       size);
 		return -1;
 	}
-    
+
 	if (i2c_transfer(adapter, msg, num) < 0)
 		return -1;
 
@@ -1193,8 +1027,8 @@
 			case I2C_SMBUS_PROC_CALL:
 				data->word = msgbuf1[0] | (msgbuf1[1] << 8);
 				break;
-  		}
-  	return 0;
+		}
+	return 0;
 }
 
 
@@ -1203,7 +1037,7 @@
                    union i2c_smbus_data * data)
 {
 	s32 res;
-        flags = flags & I2C_M_TEN;
+	flags = flags & I2C_M_TEN;
 	if (adapter->algo->smbus_xfer) {
 		I2C_LOCK(adapter);
 		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
@@ -1211,7 +1045,7 @@
 		I2C_UNLOCK(adapter);
 	} else
 		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
-                                              command,size,data);
+	                                      command,size,data);
 	return res;
 }
 
@@ -1220,22 +1054,22 @@
    backward compatibility. */ 
 u32 i2c_get_functionality (struct i2c_adapter *adap)
 {
-  if (adap->algo->functionality)
-    return adap->algo->functionality(adap);
-  else
-    return 0xffffffff;
+	if (adap->algo->functionality)
+		return adap->algo->functionality(adap);
+	else
+		return 0xffffffff;
 }
 
 int i2c_check_functionality (struct i2c_adapter *adap, u32 func)
 {
-  u32 adap_func = i2c_get_functionality (adap);
-  return (func & adap_func) == func;
+	u32 adap_func = i2c_get_functionality (adap);
+	return (func & adap_func) == func;
 }
 
 
 static int __init i2c_init(void)
 {
-        printk("i2c-core.o: i2c core module\n");
+	printk("i2c-core.o: i2c core module\n");
 	memset(adapters,0,sizeof(adapters));
 	memset(drivers,0,sizeof(drivers));
 	adap_count=0;
diff -u --recursive --new-file v2.3.41/linux/drivers/i2c/i2c-dev.c linux/drivers/i2c/i2c-dev.c
--- v2.3.41/linux/drivers/i2c/i2c-dev.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/i2c/i2c-dev.c	Fri Jan 28 19:36:23 2000
@@ -23,7 +23,7 @@
    But I have used so much of his original code and ideas that it seems
    only fair to recognize him as co-author -- Frodo */
 
-/* $Id: i2c-dev.c,v 1.18 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-dev.c,v 1.25 2000/01/26 14:14:20 frodo Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -34,34 +34,8 @@
 /* If you want debugging uncomment: */
 /* #define DEBUG */
 
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,51)
 #include <linux/init.h>
-#else
-#define __init
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,4))
-#define copy_from_user memcpy_fromfs
-#define copy_to_user memcpy_tofs
-#define get_user_data(to,from) ((to) = get_user(from),0)
-#else
 #include <asm/uaccess.h>
-#define get_user_data(to,from) get_user(to,from)
-#endif
-
-/* 2.0.0 kernel compatibility */
-#if LINUX_VERSION_CODE < 0x020100
-#define MODULE_AUTHOR(noone)
-#define MODULE_DESCRIPTION(none)
-#define MODULE_PARM(no,param)
-#define MODULE_PARM_DESC(no,description)
-#define EXPORT_SYMBOL(noexport)
-#define EXPORT_NO_SYMBOLS
-#endif
 
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
@@ -73,45 +47,18 @@
 
 /* struct file_operations changed too often in the 2.1 series for nice code */
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
 static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
-static long long i2cdev_lseek (struct file *file, long long offset, int origin);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long long i2cdev_llseek (struct inode *inode, struct file *file, 
-                                long long offset, int origin);
-#else
-static int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, 
-                         int origin);
-#endif
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
 static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, 
                             loff_t *offset);
 static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, 
                              loff_t *offset);
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long i2cdev_read (struct inode *inode, struct file *file, char *buf, 
-                         unsigned long count);
-static long i2cdev_write (struct inode *inode, struct file *file, 
-                          const char *buf, unsigned long offset);
-#else
-static int i2cdev_read(struct inode *inode, struct file *file, char *buf, 
-                       int count);
-static int i2cdev_write(struct inode *inode, struct file *file, 
-                        const char *buf, int count);
-#endif
 
 static int i2cdev_ioctl (struct inode *inode, struct file *file, 
                          unsigned int cmd, unsigned long arg);
 static int i2cdev_open (struct inode *inode, struct file *file);
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
 static int i2cdev_release (struct inode *inode, struct file *file);
-#else
-static void i2cdev_release (struct inode *inode, struct file *file);
-#endif
-
 
 static int i2cdev_attach_adapter(struct i2c_adapter *adap);
 static int i2cdev_detach_client(struct i2c_client *client);
@@ -127,413 +74,349 @@
 static int i2cdev_cleanup(void);
 
 static struct file_operations i2cdev_fops = {
-    i2cdev_lseek,
-    i2cdev_read,
-    i2cdev_write,
-    NULL,                   /* i2cdev_readdir  */
-    NULL,                   /* i2cdev_select   */
-    i2cdev_ioctl,
-    NULL,                   /* i2cdev_mmap     */
-    i2cdev_open,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,118)
-    NULL,                   /* i2cdev_flush    */
-#endif
-    i2cdev_release,
+	i2cdev_lseek,
+	i2cdev_read,
+	i2cdev_write,
+	NULL,			/* i2cdev_readdir	*/
+	NULL,			/* i2cdev_select	*/
+	i2cdev_ioctl,
+	NULL,			/* i2cdev_mmap		*/
+	i2cdev_open,
+	NULL,			/* i2cdev_flush		*/
+	i2cdev_release,
 };
 
 #define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
 static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
 
 static struct i2c_driver i2cdev_driver = {
-  /* name */            "i2c-dev dummy driver",
-  /* id */              I2C_DRIVERID_I2CDEV,
-  /* flags */           I2C_DF_DUMMY,
-  /* attach_adapter */  i2cdev_attach_adapter,
-  /* detach_client */   i2cdev_detach_client,
-  /* command */         i2cdev_command,
-  /* inc_use */         NULL,
-  /* dec_use */         NULL,
+	/* name */		"i2c-dev dummy driver",
+	/* id */		I2C_DRIVERID_I2CDEV,
+	/* flags */		I2C_DF_DUMMY,
+	/* attach_adapter */	i2cdev_attach_adapter,
+	/* detach_client */	i2cdev_detach_client,
+	/* command */		i2cdev_command,
+	/* inc_use */		NULL,
+	/* dec_use */		NULL,
 };
 
 static struct i2c_client i2cdev_client_template = {
-  /* name */          "I2C /dev entry",
-  /* id */            1,
-  /* flags */         0,
-  /* addr */          -1,
-  /* adapter */       NULL,
-  /* driver */        &i2cdev_driver,
-  /* data */          NULL
+	/* name */		"I2C /dev entry",
+	/* id */		1,
+	/* flags */		0,
+	/* addr */		-1,
+	/* adapter */		NULL,
+	/* driver */		&i2cdev_driver,
+	/* data */		NULL
 };
 
 static int i2cdev_initialized;
 
 /* Note that the lseek function is called llseek in 2.1 kernels. But things
    are complicated enough as is. */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
 loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
-long long i2cdev_lseek (struct file *file, long long offset, int origin)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-long long i2cdev_llseek (struct inode *inode, struct file *file, 
-                         long long offset, int origin)
-#else
-int i2cdev_lseek (struct inode *inode, struct file *file, off_t offset, 
-                  int origin)
-#endif
 {
 #ifdef DEBUG
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,56))
-   struct inode *inode = file->f_dentry->d_inode;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
-  printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n",
-         MINOR(inode->i_rdev),(long) offset,origin);
+	struct inode *inode = file->f_dentry->d_inode;
+	printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n",
+	       MINOR(inode->i_rdev),(long) offset,origin);
 #endif /* DEBUG */
-  return -ESPIPE;
+	return -ESPIPE;
 }
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
 static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
                             loff_t *offset)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long i2cdev_read (struct inode *inode, struct file *file, char *buf,
-                         unsigned long count)
-#else
-static int i2cdev_read(struct inode *inode, struct file *file, char *buf,
-                       int count)
-#endif
 {
-  char *tmp;
-  int ret;
+	char *tmp;
+	int ret;
 
 #ifdef DEBUG
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
-   struct inode *inode = file->f_dentry->d_inode;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
+	struct inode *inode = file->f_dentry->d_inode;
 #endif /* DEBUG */
 
-  struct i2c_client *client = (struct i2c_client *)file->private_data;
+	struct i2c_client *client = (struct i2c_client *)file->private_data;
 
-  /* copy user space data to kernel space. */
-  tmp = kmalloc(count,GFP_KERNEL);
-  if (tmp==NULL)
-     return -ENOMEM;
+	/* copy user space data to kernel space. */
+	tmp = kmalloc(count,GFP_KERNEL);
+	if (tmp==NULL)
+		return -ENOMEM;
 
 #ifdef DEBUG
-  printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),count);
+	printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
+	       count);
 #endif
 
-  ret = i2c_master_recv(client,tmp,count);
-  copy_to_user(buf,tmp,count);
-  kfree(tmp);
-  return ret;
+	ret = i2c_master_recv(client,tmp,count);
+	if (! ret)
+		ret = copy_to_user(buf,tmp,count)?-EFAULT:0;
+	kfree(tmp);
+	return ret;
 }
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
 static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
                              loff_t *offset)
-#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0))
-static long i2cdev_write (struct inode *inode, struct file *file,
-                          const char *buf, unsigned long offset)
-#else
-static int i2cdev_write(struct inode *inode, struct file *file,
-                        const char *buf, int count)
-#endif
 {
-  int ret;
-  char *tmp;
-  struct i2c_client *client = (struct i2c_client *)file->private_data;
+	int ret;
+	char *tmp;
+	struct i2c_client *client = (struct i2c_client *)file->private_data;
 
 #ifdef DEBUG
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70))
-   struct inode *inode = file->f_dentry->d_inode;
-#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)) */
+	struct inode *inode = file->f_dentry->d_inode;
 #endif /* DEBUG */
 
-  /* copy user space data to kernel space. */
-  tmp = kmalloc(count,GFP_KERNEL);
-  if (tmp==NULL)
-    return -ENOMEM;
-  copy_from_user(tmp,buf,count);
-
-#ifdef DEBUG
-  printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),count);
-#endif
-  ret = i2c_master_send(client,tmp,count);
-  kfree(tmp);
-  return ret;
+	/* copy user space data to kernel space. */
+	tmp = kmalloc(count,GFP_KERNEL);
+	if (tmp==NULL)
+		return -ENOMEM;
+	if (copy_from_user(tmp,buf,count)) {
+		kfree(tmp);
+		return -EFAULT;
+	}
+
+#ifdef DEBUG
+	printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
+	       count);
+#endif
+	ret = i2c_master_send(client,tmp,count);
+	kfree(tmp);
+	return ret;
 }
 
 int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, 
                   unsigned long arg)
 {
-  struct i2c_client *client = (struct i2c_client *)file->private_data;
-  struct i2c_smbus_ioctl_data data_arg;
-  union i2c_smbus_data temp;
-  int ver,datasize,res;
-  unsigned long funcs;
+	struct i2c_client *client = (struct i2c_client *)file->private_data;
+	struct i2c_smbus_ioctl_data data_arg;
+	union i2c_smbus_data temp;
+	int datasize,res;
+	unsigned long funcs;
 
 #ifdef DEBUG
-  printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", 
-         MINOR(inode->i_rdev),cmd, arg);
+	printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", 
+	       MINOR(inode->i_rdev),cmd, arg);
 #endif /* DEBUG */
 
-  switch ( cmd ) {
-    case I2C_SLAVE:
-    case I2C_SLAVE_FORCE:
-      if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
-        return -EINVAL;
-      if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
-        return -EBUSY;
-      client->addr = arg;
-      return 0;
-    case I2C_TENBIT:
-      if (arg)
-        client->flags |= I2C_M_TEN;
-      else
-        client->flags &= ~I2C_M_TEN;
-      return 0;
-    case I2C_FUNCS:
-      if (! arg) {
-#ifdef DEBUG
-        printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
-#endif
-        return -EINVAL;
-      }
-      if (verify_area(VERIFY_WRITE,(unsigned long *) arg,
-          sizeof(unsigned long))) {
-#ifdef DEBUG
-        printk("i2c-dev.o: invalid argument pointer (%ld) "
-               "in IOCTL I2C_SMBUS.\n", arg);
-#endif
-        return -EINVAL;
-      }
-      
-      funcs = i2c_get_functionality(client->adapter);
-      copy_to_user((unsigned long *)arg,&funcs,sizeof(unsigned long));
-      return 0;
-    case I2C_SMBUS:
-      if (! arg) {
-#ifdef DEBUG
-        printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
-#endif
-        return -EINVAL;
-      }
-      if (verify_area(VERIFY_READ,(struct i2c_smbus_ioctl_data *) arg,
-          sizeof(struct i2c_smbus_ioctl_data))) {
-#ifdef DEBUG
-        printk("i2c-dev.o: invalid argument pointer (%ld) "
-               "in IOCTL I2C_SMBUS.\n", arg);
-#endif
-        return -EINVAL;
-      }
-      copy_from_user(&data_arg,(struct i2c_smbus_ioctl_data *) arg,
-                     sizeof(struct i2c_smbus_ioctl_data));
-      if ((data_arg.size != I2C_SMBUS_BYTE) && 
-          (data_arg.size != I2C_SMBUS_QUICK) &&
-          (data_arg.size != I2C_SMBUS_BYTE_DATA) && 
-          (data_arg.size != I2C_SMBUS_WORD_DATA) &&
-          (data_arg.size != I2C_SMBUS_PROC_CALL) &&
-          (data_arg.size != I2C_SMBUS_BLOCK_DATA)) {
-#ifdef DEBUG
-        printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
-               data_arg.size);
-#endif
-        return -EINVAL;
-      }
-      /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, 
-         so the check is valid if size==I2C_SMBUS_QUICK too. */
-      if ((data_arg.read_write != I2C_SMBUS_READ) && 
-          (data_arg.read_write != I2C_SMBUS_WRITE)) {
-#ifdef DEBUG
-        printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
-               data_arg.read_write);
-#endif
-        return -EINVAL;
-      }
-
-      /* Note that command values are always valid! */
-
-      if ((data_arg.size == I2C_SMBUS_QUICK) ||
-          ((data_arg.size == I2C_SMBUS_BYTE) && 
-           (data_arg.read_write == I2C_SMBUS_WRITE)))
-        /* These are special: we do not use data */
-        return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
-                              data_arg.read_write, data_arg.command,
-                              data_arg.size, NULL);
-
-      if (data_arg.data == NULL) {
-#ifdef DEBUG
-        printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n");
-#endif
-        return -EINVAL;
-      }
-
-      /* This seems unlogical but it is not: if the user wants to read a
-         value, we must write that value to user memory! */
-      ver = ((data_arg.read_write == I2C_SMBUS_WRITE) && 
-             (data_arg.size != I2C_SMBUS_PROC_CALL))?VERIFY_READ:VERIFY_WRITE;
-
-      if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || (data_arg.size == I2C_SMBUS_BYTE))
-        datasize = sizeof(data_arg.data->byte);
-      else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
-               (data_arg.size == I2C_SMBUS_PROC_CALL))
-        datasize = sizeof(data_arg.data->word);
-      else /* size == I2C_SMBUS_BLOCK_DATA */
-        datasize = sizeof(data_arg.data->block);
-
-      if (verify_area(ver,data_arg.data,datasize)) {
-#ifdef DEBUG
-        printk("i2c-dev.o: invalid pointer data (%p) in ioctl I2C_SMBUS.\n",
-               data_arg.data);
-#endif
-        return -EINVAL;
-      }
-
-      if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
-          (data_arg.read_write == I2C_SMBUS_WRITE))
-        copy_from_user(&temp,data_arg.data,datasize);
-      res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                           data_arg.read_write,
-                           data_arg.command,data_arg.size,&temp);
-      if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
-                    (data_arg.read_write == I2C_SMBUS_READ)))
-        copy_to_user(data_arg.data,&temp,datasize);
-      return res;
-
-    default:
-      return i2c_control(client,cmd,arg);
-   }
-  return 0;
+	switch ( cmd ) {
+	case I2C_SLAVE:
+	case I2C_SLAVE_FORCE:
+		if ((arg > 0x3ff) || 
+		    (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
+			return -EINVAL;
+		if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
+			return -EBUSY;
+		client->addr = arg;
+		return 0;
+	case I2C_TENBIT:
+		if (arg)
+			client->flags |= I2C_M_TEN;
+		else
+			client->flags &= ~I2C_M_TEN;
+		return 0;
+	case I2C_FUNCS:
+		funcs = i2c_get_functionality(client->adapter);
+		return (copy_to_user((unsigned long *)arg,&funcs,
+		                     sizeof(unsigned long)))?-EFAULT:0;
+	case I2C_SMBUS:
+		copy_from_user_ret(&data_arg,
+		                   (struct i2c_smbus_ioctl_data *) arg,
+		                   sizeof(struct i2c_smbus_ioctl_data),
+		                   -EFAULT);
+		if ((data_arg.size != I2C_SMBUS_BYTE) && 
+		    (data_arg.size != I2C_SMBUS_QUICK) &&
+		    (data_arg.size != I2C_SMBUS_BYTE_DATA) && 
+		    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
+		    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
+		    (data_arg.size != I2C_SMBUS_BLOCK_DATA)) {
+#ifdef DEBUG
+			printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
+			       data_arg.size);
+#endif
+			return -EINVAL;
+		}
+		/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, 
+		   so the check is valid if size==I2C_SMBUS_QUICK too. */
+		if ((data_arg.read_write != I2C_SMBUS_READ) && 
+		    (data_arg.read_write != I2C_SMBUS_WRITE)) {
+#ifdef DEBUG
+			printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
+			       data_arg.read_write);
+#endif
+			return -EINVAL;
+		}
+
+		/* Note that command values are always valid! */
+
+		if ((data_arg.size == I2C_SMBUS_QUICK) ||
+		    ((data_arg.size == I2C_SMBUS_BYTE) && 
+		    (data_arg.read_write == I2C_SMBUS_WRITE)))
+			/* These are special: we do not use data */
+			return i2c_smbus_xfer(client->adapter, client->addr,
+			                      client->flags,
+			                      data_arg.read_write,
+			                      data_arg.command,
+			                      data_arg.size, NULL);
+
+		if (data_arg.data == NULL) {
+#ifdef DEBUG
+			printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n");
+#endif
+			return -EINVAL;
+		}
+
+		if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
+		    (data_arg.size == I2C_SMBUS_BYTE))
+			datasize = sizeof(data_arg.data->byte);
+		else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
+		         (data_arg.size == I2C_SMBUS_PROC_CALL))
+			datasize = sizeof(data_arg.data->word);
+		else /* size == I2C_SMBUS_BLOCK_DATA */
+			datasize = sizeof(data_arg.data->block);
+
+		if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+		    (data_arg.read_write == I2C_SMBUS_WRITE))
+			copy_from_user_ret(&temp,data_arg.data,datasize,
+			                   -EFAULT);
+		res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+		      data_arg.read_write,
+		      data_arg.command,data_arg.size,&temp);
+		if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
+		   (data_arg.read_write == I2C_SMBUS_READ)))
+			copy_to_user_ret(data_arg.data,&temp,datasize,-EFAULT);
+		return res;
+
+	default:
+		return i2c_control(client,cmd,arg);
+	}
+	return 0;
 }
 
 int i2cdev_open (struct inode *inode, struct file *file)
 {
-  unsigned int minor = MINOR(inode->i_rdev);
-  struct i2c_client *client;
+	unsigned int minor = MINOR(inode->i_rdev);
+	struct i2c_client *client;
 
-  if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
+	if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
 #ifdef DEBUG
-    printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",minor);
+		printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",
+		       minor);
 #endif
-    return -ENODEV;
-  }
+		return -ENODEV;
+	}
 
-  /* Note that we here allocate a client for later use, but we will *not*
-     register this client! Yes, this is safe. No, it is not very clean. */
-  if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
-    return -ENOMEM;
-  memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
-  client->adapter = i2cdev_adaps[minor];
-  file->private_data = client;
+	/* Note that we here allocate a client for later use, but we will *not*
+	   register this client! Yes, this is safe. No, it is not very clean. */
+	if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
+		return -ENOMEM;
+	memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
+	client->adapter = i2cdev_adaps[minor];
+	file->private_data = client;
 
-  i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
-  MOD_INC_USE_COUNT;
+	if (i2cdev_adaps[minor]->inc_use)
+		i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
+	MOD_INC_USE_COUNT;
 
 #ifdef DEBUG
-  printk("i2c-dev.o: opened i2c-%d\n",minor);
+	printk("i2c-dev.o: opened i2c-%d\n",minor);
 #endif
-  return 0;
+	return 0;
 }
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
 static int i2cdev_release (struct inode *inode, struct file *file)
-#else
-static void i2cdev_release (struct inode *inode, struct file *file)
-#endif
 {
-  unsigned int minor = MINOR(inode->i_rdev);
-   kfree(file->private_data);
-   file->private_data=NULL;
-#ifdef DEBUG
-   printk("i2c-dev.o: Closed: i2c-%d\n", minor);
-#endif
-  MOD_DEC_USE_COUNT;
-  i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,31))
-   return 0;
-#endif
+	unsigned int minor = MINOR(inode->i_rdev);
+	kfree(file->private_data);
+	file->private_data=NULL;
+#ifdef DEBUG
+	printk("i2c-dev.o: Closed: i2c-%d\n", minor);
+#endif
+	MOD_DEC_USE_COUNT;
+	if (i2cdev_adaps[minor]->dec_use)
+		i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
+	return 0;
 }
 
 int i2cdev_attach_adapter(struct i2c_adapter *adap)
 {
-  int i;
+	int i;
 
-  if ((i = i2c_adapter_id(adap)) < 0) {
-    printk("i2c-dev.o: Unknown adapter ?!?\n");
-    return -ENODEV;
-  }
-  if (i >= I2CDEV_ADAPS_MAX) {
-    printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i);
-    return -ENODEV;
-  }
-  
-  if (! i2cdev_adaps[i]) {
-    i2cdev_adaps[i] = adap;
-    printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
-  } else {
-    i2cdev_adaps[i] = NULL;
+	if ((i = i2c_adapter_id(adap)) < 0) {
+		printk("i2c-dev.o: Unknown adapter ?!?\n");
+		return -ENODEV;
+	}
+	if (i >= I2CDEV_ADAPS_MAX) {
+		printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i);
+		return -ENODEV;
+	}
+
+	if (! i2cdev_adaps[i]) {
+		i2cdev_adaps[i] = adap;
+		printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
+	} else {
+		i2cdev_adaps[i] = NULL;
 #ifdef DEBUG
-    printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
+		printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
 #endif
-  }
+	}
 
-  return 0;
+	return 0;
 }
 
 int i2cdev_detach_client(struct i2c_client *client)
 {
-  return 0;
+	return 0;
 }
 
 static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
                            void *arg)
 {
-  return -1;
+	return -1;
 }
 
 int __init i2c_dev_init(void)
 {
-  int res;
+	int res;
 
-  printk("i2c-dev.o: i2c /dev entries driver module\n");
+	printk("i2c-dev.o: i2c /dev entries driver module\n");
 
-  i2cdev_initialized = 0;
-  if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
-    printk("i2c-dev.o: unable to get major %d for i2c bus\n",I2C_MAJOR);
-    return -EIO;
-  }
-  i2cdev_initialized ++;
-
-  if ((res = i2c_add_driver(&i2cdev_driver))) {
-    printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
-    i2cdev_cleanup();
-    return res;
-  }
-  i2cdev_initialized ++;
-  return 0;
+	i2cdev_initialized = 0;
+	if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
+		printk("i2c-dev.o: unable to get major %d for i2c bus\n",
+		       I2C_MAJOR);
+		return -EIO;
+	}
+	i2cdev_initialized ++;
+
+	if ((res = i2c_add_driver(&i2cdev_driver))) {
+		printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
+		i2cdev_cleanup();
+		return res;
+	}
+	i2cdev_initialized ++;
+	return 0;
 }
 
 int i2cdev_cleanup(void)
 {
-  int res;
+	int res;
 
-  if (i2cdev_initialized >= 2) {
-    if ((res = i2c_del_driver(&i2cdev_driver))) {
-      printk("i2c-dev.o: Driver deregistration failed, "
-             "module not removed.\n");
-      return res;
-    }
-    i2cdev_initialized ++;
-  }
-
-  if (i2cdev_initialized >= 1) {
-    if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
-      printk("i2c-dev.o: unable to release major %d for i2c bus\n",I2C_MAJOR);
-      return res;
-    }
-    i2cdev_initialized --;
-  }
-  return 0;
+	if (i2cdev_initialized >= 2) {
+		if ((res = i2c_del_driver(&i2cdev_driver))) {
+			printk("i2c-dev.o: Driver deregistration failed, "
+			       "module not removed.\n");
+			return res;
+		}
+	i2cdev_initialized ++;
+	}
+
+	if (i2cdev_initialized >= 1) {
+		if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
+			printk("i2c-dev.o: unable to release major %d for i2c bus\n",
+			       I2C_MAJOR);
+			return res;
+		}
+		i2cdev_initialized --;
+	}
+	return 0;
 }
 
 EXPORT_NO_SYMBOLS;
@@ -545,12 +428,12 @@
 
 int init_module(void)
 {
-  return i2c_dev_init();
+	return i2c_dev_init();
 }
 
 int cleanup_module(void)
 {
-  return i2cdev_cleanup();
+	return i2cdev_cleanup();
 }
 
 #endif /* def MODULE */
diff -u --recursive --new-file v2.3.41/linux/drivers/i2c/i2c-elektor.c linux/drivers/i2c/i2c-elektor.c
--- v2.3.41/linux/drivers/i2c/i2c-elektor.c	Tue Jan  4 13:57:17 2000
+++ linux/drivers/i2c/i2c-elektor.c	Fri Jan 28 19:36:23 2000
@@ -22,7 +22,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-elektor.c,v 1.13 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-elektor.c,v 1.16 2000/01/24 02:06:33 mds Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/ioport.h>
@@ -30,24 +30,10 @@
 #include <linux/delay.h>
 #include <linux/malloc.h>
 #include <linux/version.h>
-#if LINUX_VERSION_CODE >= 0x020135
 #include <linux/init.h>
-#else
-#define __init 
-#endif
 #include <asm/irq.h>
 #include <asm/io.h>
 
-/* 2.0.0 kernel compatibility */
-#if LINUX_VERSION_CODE < 0x020100
-#define MODULE_AUTHOR(noone)
-#define MODULE_DESCRIPTION(none)
-#define MODULE_PARM(no,param)
-#define MODULE_PARM_DESC(no,description)
-#define EXPORT_SYMBOL(noexport)
-#define EXPORT_NO_SYMBOLS
-#endif
-
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pcf.h>
 #include <linux/i2c-elektor.h>
@@ -87,56 +73,48 @@
 
 static void pcf_isa_setbyte(void *data, int ctl, int val)
 {
-   if (ctl) {
-      if (gpi.pi_irq > 0) {
-	 DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val|I2C_PCF_ENI));
-	 outb(val | I2C_PCF_ENI, CTRL);
-      } else {
-	 DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val));
-	 outb(val, CTRL);
-      }
-   } else {
-      DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val));
-      outb(val, DATA);
-   }
+	if (ctl) {
+		if (gpi.pi_irq > 0) {
+			DEB3(printk("i2c-elektor.o: Write control 0x%x\n",
+			     val|I2C_PCF_ENI));
+			outb(val | I2C_PCF_ENI, CTRL);
+		} else {
+			 DEB3(printk("i2c-elektor.o: Write control 0x%x\n", val));
+			 outb(val, CTRL);
+		}
+	} else {
+		DEB3(printk("i2c-elektor.o: Write data 0x%x\n", val));
+		outb(val, DATA);
+	}
 }
 
 static int pcf_isa_getbyte(void *data, int ctl)
 {
-   int val;
+	int val;
 
-   if (ctl) {
-      val = inb(CTRL);
-      DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val));
-   } else {
-      val = inb(DATA);
-      DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val));
-   }
-   return (val);
+	if (ctl) {
+		val = inb(CTRL);
+		DEB3(printk("i2c-elektor.o: Read control 0x%x\n", val));
+	} else {
+		val = inb(DATA);
+		DEB3(printk("i2c-elektor.o: Read data 0x%x\n", val));
+	}
+	return (val);
 }
 
 static int pcf_isa_getown(void *data)
 {
-   return (gpi.pi_own);
+	return (gpi.pi_own);
 }
 
 
 static int pcf_isa_getclock(void *data)
 {
-   return (gpi.pi_clock);
+	return (gpi.pi_clock);
 }
 
 
 
-#if LINUX_VERSION_CODE < 0x02017f
-static void schedule_timeout(int j)
-{
-	current->state   = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies + j;
-	schedule();
-}
-#endif
-
 #if 0
 static void pcf_isa_sleep(unsigned long timeout)
 {
@@ -147,64 +125,53 @@
 
 static void pcf_isa_waitforpin(void) {
 
-   int timeout = 2;
+	int timeout = 2;
 
-   if (gpi.pi_irq > 0) {
-      cli();
-      if (pcf_pending == 0) {
-#if LINUX_VERSION_CODE < 0x02017f
-	 current->timeout = jiffies + timeout * HZ;
-	 interruptible_sleep_on(&pcf_wait);
-#else
-	 interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
-#endif
-      }
-      else
-	 pcf_pending = 0;
-      sti();
-#if LINUX_VERSION_CODE < 0x02017f
-      current->timeout = 0;
-#endif
-   }
-   else {
-      udelay(100);
-   }
+	if (gpi.pi_irq > 0) {
+		cli();
+	if (pcf_pending == 0) {
+		interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
+	} else
+		pcf_pending = 0;
+		sti();
+	} else {
+		udelay(100);
+	}
 }
 
 
 static void pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
-
-   pcf_pending = 1;
-   wake_up_interruptible(&pcf_wait);
+	pcf_pending = 1;
+	wake_up_interruptible(&pcf_wait);
 }
 
 
 static int pcf_isa_init(void)
 {
-   if (check_region(gpi.pi_base, 2) < 0 ) {
-      return -ENODEV;
-   } else {
-      request_region(gpi.pi_base, 2, "i2c (isa bus adapter)");
-   }
-   if (gpi.pi_irq > 0) {
-      if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) {
-	 printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq);
-	 gpi.pi_irq = 0;
-      }
-      else
-	 enable_irq(gpi.pi_irq);
-   }
-   return 0;
+	if (check_region(gpi.pi_base, 2) < 0 ) {
+		return -ENODEV;
+	} else {
+		request_region(gpi.pi_base, 2, "i2c (isa bus adapter)");
+	}
+	if (gpi.pi_irq > 0) {
+		if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0)
+		    < 0) {
+		printk("i2c-elektor.o: Request irq%d failed\n", gpi.pi_irq);
+		gpi.pi_irq = 0;
+	} else
+		enable_irq(gpi.pi_irq);
+	}
+	return 0;
 }
 
 
 static void pcf_isa_exit(void)
 {
-   if (gpi.pi_irq > 0) {
-      disable_irq(gpi.pi_irq);
-      free_irq(gpi.pi_irq, 0);
-   }
-   release_region(gpi.pi_base , 2);
+	if (gpi.pi_irq > 0) {
+		disable_irq(gpi.pi_irq);
+		free_irq(gpi.pi_irq, 0);
+	}
+	release_region(gpi.pi_base , 2);
 }
 
 
@@ -222,14 +189,14 @@
 static void pcf_isa_inc_use(struct i2c_adapter *adap)
 {
 #ifdef MODULE
-  MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 #endif
 }
 
 static void pcf_isa_dec_use(struct i2c_adapter *adap)
 {
 #ifdef MODULE
-  MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 #endif
 }
 
@@ -262,41 +229,41 @@
 int __init i2c_pcfisa_init(void) 
 {
 
-   struct i2c_pcf_isa *pisa = &gpi;
+	struct i2c_pcf_isa *pisa = &gpi;
 
-   printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n");
-   if (base == 0)
-      pisa->pi_base = DEFAULT_BASE;
-   else
-      pisa->pi_base = base;
-
-   if (irq == 0)
-      pisa->pi_irq = DEFAULT_IRQ;
-   else
-      pisa->pi_irq = irq;
-
-   if (clock == 0)
-      pisa->pi_clock = DEFAULT_CLOCK;
-   else
-      pisa->pi_clock = clock;
-
-   if (own == 0)
-      pisa->pi_own = DEFAULT_OWN;
-   else
-      pisa->pi_own = own;
+	printk("i2c-elektor.o: i2c pcf8584-isa adapter module\n");
+	if (base == 0)
+		pisa->pi_base = DEFAULT_BASE;
+	else
+		pisa->pi_base = base;
+
+	if (irq == 0)
+		pisa->pi_irq = DEFAULT_IRQ;
+	else
+		pisa->pi_irq = irq;
+
+	if (clock == 0)
+		pisa->pi_clock = DEFAULT_CLOCK;
+	else
+		pisa->pi_clock = clock;
+
+	if (own == 0)
+		pisa->pi_own = DEFAULT_OWN;
+	else
+		pisa->pi_own = own;
 
-   pcf_isa_data.data = (void *)pisa;
+	pcf_isa_data.data = (void *)pisa;
 #if (LINUX_VERSION_CODE >= 0x020301)
-   init_waitqueue_head(&pcf_wait);
+	init_waitqueue_head(&pcf_wait);
 #endif
-   if (pcf_isa_init() == 0) {
-      if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
-        return -ENODEV;
-   } else {
-      return -ENODEV;
-   }
-   printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base);
-   return 0;
+	if (pcf_isa_init() == 0) {
+		if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
+			return -ENODEV;
+	} else {
+		return -ENODEV;
+	}
+	printk("i2c-elektor.o: found device at %#x.\n", pisa->pi_base);
+	return 0;
 }
 
 
@@ -313,7 +280,7 @@
 
 int init_module(void) 
 {
-   return i2c_pcfisa_init();
+	return i2c_pcfisa_init();
 }
 
 void cleanup_module(void) 
diff -u --recursive --new-file v2.3.41/linux/drivers/i2c/i2c-pcf8584.h linux/drivers/i2c/i2c-pcf8584.h
--- v2.3.41/linux/drivers/i2c/i2c-pcf8584.h	Tue Jan  4 13:57:17 2000
+++ linux/drivers/i2c/i2c-pcf8584.h	Fri Jan 28 19:36:23 2000
@@ -21,20 +21,20 @@
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-pcf8584.h,v 1.2 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-pcf8584.h,v 1.3 2000/01/18 23:54:07 frodo Exp $ */
 
 #ifndef I2C_PCF8584_H
 #define I2C_PCF8584_H 1
 
 /* ----- Control register bits ----------------------------------------	*/
-#define I2C_PCF_PIN  0x80
-#define I2C_PCF_ESO  0x40
-#define I2C_PCF_ES1  0x20
-#define I2C_PCF_ES2  0x10
-#define I2C_PCF_ENI  0x08
-#define I2C_PCF_STA  0x04
-#define I2C_PCF_STO  0x02
-#define I2C_PCF_ACK  0x01
+#define I2C_PCF_PIN	0x80
+#define I2C_PCF_ESO	0x40
+#define I2C_PCF_ES1	0x20
+#define I2C_PCF_ES2	0x10
+#define I2C_PCF_ENI	0x08
+#define I2C_PCF_STA	0x04
+#define I2C_PCF_STO	0x02
+#define I2C_PCF_ACK	0x01
 
 #define I2C_PCF_START    (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
 #define I2C_PCF_STOP     (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
@@ -45,7 +45,7 @@
 /*#define I2C_PCF_PIN  0x80    as above*/
 
 #define I2C_PCF_INI 0x40   /* 1 if not initialized */
-#define I2C_PCF_STS 0x20   
+#define I2C_PCF_STS 0x20
 #define I2C_PCF_BER 0x10
 #define I2C_PCF_AD0 0x08
 #define I2C_PCF_LRB 0x08
@@ -54,17 +54,17 @@
 #define I2C_PCF_BB  0x01
 
 /* ----- Chip clock frequencies ---------------------------------------	*/
-#define I2C_PCF_CLK3    0x00
-#define I2C_PCF_CLK443  0x10
-#define I2C_PCF_CLK6    0x14
-#define I2C_PCF_CLK8    0x18
-#define I2C_PCF_CLK12   0x1c
+#define I2C_PCF_CLK3	0x00
+#define I2C_PCF_CLK443	0x10
+#define I2C_PCF_CLK6	0x14
+#define I2C_PCF_CLK	0x18
+#define I2C_PCF_CLK12	0x1c
 
 /* ----- transmission frequencies -------------------------------------	*/
-#define I2C_PCF_TRNS90 0x00  /*  90 kHz */
-#define I2C_PCF_TRNS45 0x01  /*  45 kHz */
-#define I2C_PCF_TRNS11 0x02  /*  11 kHz */
-#define I2C_PCF_TRNS15 0x03  /* 1.5 kHz */
+#define I2C_PCF_TRNS90 0x00	/*  90 kHz */
+#define I2C_PCF_TRNS45 0x01	/*  45 kHz */
+#define I2C_PCF_TRNS11 0x02	/*  11 kHz */
+#define I2C_PCF_TRNS15 0x03	/* 1.5 kHz */
 
 
 /* ----- Access to internal registers according to ES1,ES2 ------------	*/
diff -u --recursive --new-file v2.3.41/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- v2.3.41/linux/drivers/ieee1394/ieee1394_syms.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/ieee1394_syms.c	Mon Jan 31 10:13:03 2000
@@ -39,6 +39,7 @@
 EXPORT_SYMBOL(hpsb_make_readbpacket);
 EXPORT_SYMBOL(hpsb_make_writeqpacket);
 EXPORT_SYMBOL(hpsb_make_writebpacket);
+EXPORT_SYMBOL(hpsb_make_lockpacket);
 EXPORT_SYMBOL(hpsb_read);
 EXPORT_SYMBOL(hpsb_write);
 EXPORT_SYMBOL(hpsb_lock);
diff -u --recursive --new-file v2.3.41/linux/drivers/ieee1394/ieee1394_transactions.c linux/drivers/ieee1394/ieee1394_transactions.c
--- v2.3.41/linux/drivers/ieee1394/ieee1394_transactions.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/ieee1394_transactions.c	Mon Jan 31 10:13:03 2000
@@ -329,6 +329,30 @@
         return p;
 }
 
+struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
+                                         u64 addr, int extcode)
+{
+        struct hpsb_packet *p;
+
+        p = alloc_hpsb_packet(8);
+        if (!p) return NULL;
+
+        p->host = host;
+        p->tlabel = get_tlabel(host, node, 1);
+        p->node_id = node;
+
+        switch (extcode) {
+        case EXTCODE_FETCH_ADD:
+        case EXTCODE_LITTLE_ADD:
+                fill_async_lock(p, addr, extcode, 4);
+                break;
+        default:
+                fill_async_lock(p, addr, extcode, 8);
+                break;
+        }
+
+        return p;
+}
 
 /*
  * FIXME - these functions should probably read from / write to user space to
diff -u --recursive --new-file v2.3.41/linux/drivers/ieee1394/ieee1394_transactions.h linux/drivers/ieee1394/ieee1394_transactions.h
--- v2.3.41/linux/drivers/ieee1394/ieee1394_transactions.h	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/ieee1394_transactions.h	Mon Jan 31 10:13:03 2000
@@ -39,6 +39,9 @@
 struct hpsb_packet *hpsb_make_writebpacket(struct hpsb_host *host,
                                            nodeid_t node, u64 addr,
                                            size_t length);
+struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
+                                         u64 addr, int extcode);
+
 
 /*
  * hpsb_packet_success - Make sense of the ack and reply codes and
diff -u --recursive --new-file v2.3.41/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- v2.3.41/linux/drivers/ieee1394/ohci1394.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/ohci1394.c	Mon Jan 31 23:43:51 2000
@@ -1,5 +1,5 @@
 /*
- * ti_ohci1394.c - Texas Instruments Ohci1394 driver
+ * ohci1394.c - driver for OHCI 1394 boards
  * Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
  *                        Gord Peters <GordPeters@smarttech.com>
  *
@@ -18,6 +18,7 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
@@ -40,8 +41,6 @@
 #include "ieee1394_core.h"
 #include "ohci1394.h"
 
-#undef CONFIG_PROC_FS
-
 /* print general (card independent) information */
 #define PRINT_G(level, fmt, args...) \
 printk(level "ohci1394: " fmt "\n" , ## args)
@@ -68,7 +67,6 @@
  * IEEE-1394 functionality section *
  ***********************************/
 
-
 #if 0 /* not needed at this time */
 static int get_phy_reg(struct ti_ohci *ohci, int addr) 
 {
@@ -324,31 +322,53 @@
 	}
 
 	/* Initialize AR dma */
-	ohci->AR_resp_prg->control=0x283C << 16 | AR_RESP_BUF_SIZE;
-	ohci->AR_resp_prg->address=virt_to_bus(ohci->AR_resp_buf);
-	ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
-	PRINT(KERN_INFO, ohci->id, "AR control: %x",
-	      ohci->AR_resp_prg->control);
-	PRINT(KERN_INFO, ohci->id, "AR status: %x %d",
-	      ohci->AR_resp_prg->status & 0xffff,
-	      ohci->AR_resp_prg->status & 0xffff);
-
-	/* Tell the controller where the AR program is */
-	reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
-		  virt_to_bus(ohci->AR_resp_prg)|0x00000001);
+	/* make sure the context isn't running, dead, or active */
+	if (!(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x00008F00)) {
 
-#if 1
-        /* Accept phy packets into AR request context */
-        reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
-#endif
+                /* initialize AR program */
+                for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+
+			/* end of descriptor list? */
+                        if ((i + 1) < AR_RESP_NUM_DESC) {
+                                ohci->AR_resp_prg[i]->control=
+				  (0x283C << 16) | AR_RESP_BUF_SIZE;
+                                ohci->AR_resp_prg[i]->branchAddress=
+				  (virt_to_bus(ohci->AR_resp_prg[i + 1])
+                                         & 0xfffffff0) | 0x1;
+                        } else {
+                                ohci->AR_resp_prg[i]->control=
+                                        (0x283C << 16) | AR_RESP_BUF_SIZE;
+                                ohci->AR_resp_prg[i]->branchAddress=
+                                        (virt_to_bus(ohci->AR_resp_prg[0])
+                                         & 0xfffffff0) | 0x1;
+                        }
+
+                        ohci->AR_resp_prg[i]->address=
+                                virt_to_bus(ohci->AR_resp_buf[i]);
+                        ohci->AR_resp_prg[i]->status= AR_RESP_BUF_SIZE;
+		}
+
+		/* Tell the controller where the first AR program is */
+		reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
+			  virt_to_bus(ohci->AR_resp_prg[0]) | 0x1 );
+
+		/* Accept phy packets into AR request context */
+		reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400);
+
+		/* Run AR context */
+		reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
+	}
 
-	/* Run AR context */
-	reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000);
+	/* Specify AT retries */
+	reg_write(ohci, OHCI1394_ATRetries, 
+		  OHCI1394_MAX_AT_REQ_RETRIES |
+		  (OHCI1394_MAX_AT_RESP_RETRIES<<4) |
+		  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
 
 #ifndef __BIG_ENDIAN
-	reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
-#else
 	reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
+#else
+	reg_write(ohci, OHCI1394_HCControlSet, 0x40000000);
 #endif
 
 	/* Enable interrupts */
@@ -386,8 +406,9 @@
 	int i=0;
 	struct hpsb_packet *packet = ohci->async_queue;
 	struct dma_cmd prg;
+#if 0
 	quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg;
-
+#endif
 	//HPSB_TRACE();
 
         /* stop the channel program if it's still running */
@@ -435,14 +456,14 @@
                         prg.status = 0;
                         memcpy(ohci->AT_req_prg, &prg, 16);
                         memcpy(ohci->AT_req_prg + 1, packet->header, 16);
-
+#if 0
                         PRINT(KERN_INFO, ohci->id,
                               "dma_cmd: %08x %08x %08x %08x",
                               *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
                         PRINT(KERN_INFO, ohci->id,
                               "header: %08x %08x %08x %08x",
                               *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7));
-
+#endif
                         reg_write(ohci, OHCI1394_AsReqTrCommandPtr, 
                                   virt_to_bus(ohci->AT_req_prg)|0x2);
                 }
@@ -455,11 +476,11 @@
                 prg.branchAddress = 0;
                 prg.status = 0;
                 memcpy(ohci->AT_req_prg, &prg, 16);
-
+#if 0
                 PRINT(KERN_INFO, ohci->id,
                       "dma_cmd: %08x %08x %08x %08x",
                       *ptr, *(ptr+1), *(ptr+2), *(ptr+3));
-
+#endif
                 reg_write(ohci, OHCI1394_AsReqTrCommandPtr, 
                           virt_to_bus(ohci->AT_req_prg)|0x2);
         }
@@ -638,6 +659,26 @@
  * Global stuff (interrupt handler, init/shutdown code) *
  ********************************************************/
 
+static void stop_ar_resp_context(struct ti_ohci *ohci, char *msg)
+{
+	int i=0;
+
+	/* stop the channel program if it's still running */
+	reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
+   
+	/* Wait until it effectively stops */
+	while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) 
+	       & 0x400) {
+		i++;
+		if (i>5000) {
+			PRINT(KERN_ERR, ohci->id, 
+			      "runaway loop in Dma Ar Resp. bailing out...");
+			break;
+		}
+	}
+	PRINT(KERN_ERR, ohci->id, "%s\n async response receive dma stopped\n", msg);
+}
+
 static void ohci_irq_handler(int irq, void *dev_id,
                              struct pt_regs *regs_are_unused)
 {
@@ -656,15 +697,14 @@
 	   event,reg_read(ohci, OHCI1394_IntMaskSet)); */
 
 	if (event & OHCI1394_busReset) {
+#if 0
 		PRINT(KERN_INFO, ohci->id, "bus reset interrupt");
+#endif
 		if (!host->in_bus_reset) {
 			hpsb_bus_reset(host);
 		}
 		ohci->NumBusResets++;
 	}
-	if (event & OHCI1394_reqTxComplete) {
-		PRINT(KERN_INFO, ohci->id, "reqTxComplete int received");
-	}
 	if (event & OHCI1394_RQPkt) {
 		PRINT(KERN_INFO, ohci->id, "RQPkt int received");
 	}
@@ -673,58 +713,55 @@
 		      reg_read(ohci, OHCI1394_AsReqRcvContextControlSet));
 	}
 	if (event & OHCI1394_RSPkt) {
-		int rcv_bytes;
-		int i=0;
+		unsigned int idx,offset,rescount;
 
-		/* we calculate the number of received bytes from the
-		   residual count field */
-		rcv_bytes = AR_RESP_BUF_SIZE - 
-		  (ohci->AR_resp_prg->status & 0xFFFF);
-
-		PRINT(KERN_INFO, ohci->id, "AR_status 0x%x %d, %d bytes read", 
-		      ohci->AR_resp_prg->status, 
-		      ohci->AR_resp_prg->status & 0xffff, 
-		      rcv_bytes);
-
-		ohci->AR_resp_active = 0;
-
-		if ((ohci->AR_resp_prg->status & 0x84000000) 
-		    && (ohci->AR_resp_prg->status & 0xFFFF) >= 8 ) {
-			hpsb_packet_received(host, ohci->AR_resp_buf, 
-					     rcv_bytes);
-		} else {
-			//HPSB_TRACE();
-			PRINT(KERN_ERR, ohci->id, 
-			      "AR resp DMA program status value 0x%x is incorrect!",
-			      ohci->AR_resp_prg->status);
-		}
+                spin_lock(&ohci->AR_resp_lock);
 
+		idx = ohci->AR_resp_buf_th_ind;
+		offset = ohci->AR_resp_buf_th_offset;
 
-		/* --------------- FIXME ---------------------------------
-		   this is a complete hack... we stop the dma prg
-		   and start it again so as to reset the dma buffer address
-		   Very slow, very bad design... to change ASAP */
-		  
-		/* stop the channel program if it's still running */
-		reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000);
-   
-		/* Wait until it effectively stops */
-		while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) 
-		       & 0x400) {
-			i++;
-			if (i>5000) {
-				PRINT(KERN_ERR, ohci->id, 
-				      "runaway loop in DmaAT. bailing out...");
-				break;
+		rescount = ohci->AR_resp_prg[idx]->status&0xffff;
+		ohci->AR_resp_bytes_left +=  AR_RESP_BUF_SIZE - rescount - offset;
+		offset = AR_RESP_BUF_SIZE - rescount;
+
+		if (!rescount) { /* We cross a buffer boundary */
+			idx = (idx+1) % AR_RESP_NUM_DESC;
+
+#if 0 
+			/* This bit of code does not work */
+			/* Let's see how many bytes were written in the async response 
+			   receive buf since last interrupt. This is done by finding 
+			   the next active context (See OHCI Spec p91) */
+			while (ohci->AR_resp_bytes_left <= AR_RESP_TOTAL_BUF_SIZE) {
+				if (ohci->AR_resp_prg[idx]->status&0x04000000) break;
+				idx = (idx+1) % AR_RESP_NUM_DESC;
+				PRINT(KERN_INFO,ohci->id,"crossing more than one buffer boundary !!!");
+				ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE;
 			}
+#endif 
+			/* ASSUMPTION: only one buffer boundary is crossed */
+			rescount = ohci->AR_resp_prg[idx]->status&0xffff;
+			offset = AR_RESP_BUF_SIZE - rescount;
+			ohci->AR_resp_bytes_left += offset;
+		}
+		if (offset==AR_RESP_BUF_SIZE) {
+			offset=0;
+			idx = (idx+1) % AR_RESP_NUM_DESC;
 		}
+		ohci->AR_resp_buf_th_ind = idx;
+		ohci->AR_resp_buf_th_offset = offset;
 
-		reg_write(ohci, OHCI1394_AsRspRcvCommandPtr,
-			  virt_to_bus(ohci->AR_resp_prg)|0x00000001);
-		ohci->AR_resp_prg->status=AR_RESP_BUF_SIZE;
-		reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x8000);
+                /* is buffer processing too slow? (all buffers used) */
+		if (ohci->AR_resp_bytes_left > AR_RESP_TOTAL_BUF_SIZE) {
+			stop_ar_resp_context(ohci,"async response receive processing too slow");
+                        spin_unlock(&ohci->AR_resp_lock);
+			return;
+		}
+                spin_unlock(&ohci->AR_resp_lock);
 
-		/* ---------------- end of FIXME --------------------------*/
+		/* queue bottom half in immediate queue */
+		queue_task(&ohci->AR_resp_pdl_task, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
 	}
 	if (event & OHCI1394_isochRx) {
 		quadlet_t isoRecvIntEvent;
@@ -826,8 +863,10 @@
 				send_next_async(ohci);
 			}
 			spin_unlock(&ohci->async_queue_lock);
+#if 0
 			PRINT(KERN_INFO,ohci->id,
 			      "packet sent with ack code %d",ack);
+#endif
 			hpsb_packet_sent(host, packet, ack);	    
 		} else 
 		  PRINT(KERN_INFO,ohci->id,
@@ -839,6 +878,129 @@
 	ohci->NumInterrupts++;
 }
 
+
+/* This is the bottom half that processes async response receive descriptor buffers. */
+static void ohci_ar_resp_proc_desc(void *data)
+{
+	quadlet_t *buf_ptr;
+	char *split_ptr;
+	unsigned int split_left;
+	struct ti_ohci *ohci= (struct ti_ohci*)data;
+        unsigned int packet_length;
+        unsigned int idx,offset,tcode;
+        unsigned long flags;
+	char msg[256];
+
+        spin_lock_irqsave(&ohci->AR_resp_lock, flags);
+
+	idx = ohci->AR_resp_buf_bh_ind;
+	offset = ohci->AR_resp_buf_bh_offset;
+
+	buf_ptr = ohci->AR_resp_buf[idx];
+	buf_ptr += offset/4;
+
+        while(ohci->AR_resp_bytes_left > 0) {
+
+                /* check to see if a fatal error occurred */
+                if ((ohci->AR_resp_prg[idx]->status >> 16) & 0x800) {
+			sprintf(msg,"fatal async response receive error -- status is %d",
+				ohci->AR_resp_prg[idx]->status & 0x1F);
+			stop_ar_resp_context(ohci, msg);
+                        spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+                        return;
+                }
+
+                spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+
+		/* Let's see what kind of packet is in there */
+		tcode = (buf_ptr[0]>>4)&0xf;
+		if (tcode==2) /* no-data receive */
+		  packet_length=16;
+		else if (tcode==6) /* quadlet receive */
+		  packet_length=20;
+		else if (tcode==7) { /* block receive */
+			/* Where is the data length ? */
+			if (offset+12>=AR_RESP_BUF_SIZE) 
+			  packet_length=(ohci->AR_resp_buf[(idx+1)%AR_RESP_NUM_DESC]
+					 [3-(AR_RESP_BUF_SIZE-offset)/4]>>16)+20;
+			else 
+			  packet_length=(buf_ptr[3]>>16)+20;
+                        if (packet_length % 4)
+			  packet_length += 4 - (packet_length % 4);
+		}
+		else /* something is wrong */ {
+			sprintf(msg,"unexpected packet tcode %d in async response receive buffer",tcode);
+			stop_ar_resp_context(ohci,msg);
+			return;
+		}
+		if ((offset+packet_length)>AR_RESP_BUF_SIZE) {
+			/* we have a split packet */
+			if (packet_length>AR_RESP_SPLIT_PACKET_BUF_SIZE) {
+				sprintf(msg,"packet size %d bytes exceed split packet buffer size %d bytes",
+					packet_length,AR_RESP_SPLIT_PACKET_BUF_SIZE);
+				stop_ar_resp_context(ohci, msg);
+				return;
+			}
+			split_left = packet_length;
+			split_ptr = (char *)ohci->AR_resp_spb;
+			while (split_left>0) {
+				memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE-offset);
+				split_left -= AR_RESP_BUF_SIZE-offset;
+				split_ptr += AR_RESP_BUF_SIZE-offset;
+				ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+				idx = (idx+1) % AR_RESP_NUM_DESC;
+				buf_ptr = ohci->AR_resp_buf[idx];
+				offset=0;
+				while (split_left >= AR_RESP_BUF_SIZE) {
+					memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE);
+					split_ptr += AR_RESP_BUF_SIZE;
+					split_left -= AR_RESP_BUF_SIZE;
+					ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+					idx = (idx+1) % AR_RESP_NUM_DESC;
+					buf_ptr = ohci->AR_resp_buf[idx];
+				}
+				if (split_left>0) {
+					memcpy(split_ptr,buf_ptr,split_left);
+					offset = split_left;
+					split_left=0;
+					buf_ptr += split_left/4;
+				}
+			}
+#if 0
+			PRINT(KERN_INFO,ohci->id,"AR resp: received split packet tcode=%d length=%d",
+			      tcode,packet_length);
+#endif
+			hpsb_packet_received(ohci->host, ohci->AR_resp_spb, packet_length);
+			ohci->AR_resp_bytes_left -= packet_length;
+		}
+		else {
+#if 0
+			PRINT(KERN_INFO,ohci->id,"AR resp: received packet tcode=%d length=%d",
+			      tcode,packet_length);
+#endif
+			hpsb_packet_received(ohci->host, buf_ptr, packet_length);
+			offset += packet_length;
+			buf_ptr += packet_length/4;
+			ohci->AR_resp_bytes_left -= packet_length;
+			if (offset==AR_RESP_BUF_SIZE) {
+				ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE;
+				idx = (idx+1) % AR_RESP_NUM_DESC;
+				buf_ptr = ohci->AR_resp_buf[idx];
+				offset=0;
+			}
+		}
+		
+	}
+	
+	if (ohci->AR_resp_bytes_left<0) 
+	  stop_ar_resp_context(ohci, "Sync problem in AR resp dma buffer");
+
+	ohci->AR_resp_buf_bh_ind = idx;
+	ohci->AR_resp_buf_bh_offset = offset;
+
+        spin_unlock_irqrestore(&ohci->AR_resp_lock, flags);
+}
+
 /* This is the bottom half that processes iso receive descriptor buffers. */
 static void ohci_ir_proc_desc(void *data)
 {
@@ -1023,23 +1185,61 @@
 		FAIL("failed to allocate DMA buffer for self-id packets");
 	}
 
-	/* AR dma buffer allocation */
-	ohci->AR_resp_buf = kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
-	if (ohci->AR_resp_buf != NULL) {
-		memset(ohci->AR_resp_buf, 0, AR_RESP_BUF_SIZE);
-	} else {
-		FAIL("failed to allocate AR response DMA buffer");
+	/* AR dma buffer and program allocation */
+	ohci->AR_resp_buf=
+	        kmalloc(AR_RESP_NUM_DESC * sizeof(quadlet_t*),
+			GFP_KERNEL);
+
+	if (ohci->AR_resp_buf == NULL) {
+		FAIL("failed to allocate AR response receive DMA buffer");
 	}
 
-	/* AR dma program allocation */
-	ohci->AR_resp_prg = (struct dma_cmd *) kmalloc(AR_RESP_PRG_SIZE, 
-						       GFP_KERNEL);
-	if (ohci->AR_resp_prg != NULL) {
-		memset(ohci->AR_resp_prg, 0, AR_RESP_PRG_SIZE);
-	} else {
-		FAIL("failed to allocate AR response DMA program");
+	ohci->AR_resp_prg=
+		kmalloc(AR_RESP_NUM_DESC * sizeof(struct dma_cmd*),
+			GFP_KERNEL);
+
+	if (ohci->AR_resp_prg == NULL) {
+		FAIL("failed to allocate AR response receive DMA program");
 	}
 
+	ohci->AR_resp_spb= kmalloc(AR_RESP_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL);
+
+	if (ohci->AR_resp_spb == NULL) {
+		FAIL("failed to allocate AR response split packet buffer");
+	}
+
+	for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+                ohci->AR_resp_buf[i]= kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL);
+
+                if (ohci->AR_resp_buf[i] != NULL) {
+                        memset(ohci->AR_resp_buf[i], 0, AR_RESP_BUF_SIZE);
+                } else {
+                        FAIL("failed to allocate AR response DMA buffer");
+                }
+
+                ohci->AR_resp_prg[i]= kmalloc(sizeof(struct dma_cmd),
+                                                   GFP_KERNEL);
+
+                if (ohci->AR_resp_prg[i] != NULL) {
+                        memset(ohci->AR_resp_prg[i], 0,
+                               sizeof(struct dma_cmd));
+                } else {
+                        FAIL("failed to allocate AR response DMA buffer");
+                }
+
+	}
+
+        ohci->AR_resp_buf_th_ind = 0;
+        ohci->AR_resp_buf_th_offset = 0;
+        ohci->AR_resp_buf_bh_ind = 0;
+        ohci->AR_resp_buf_bh_offset = 0;
+        ohci->AR_resp_bytes_left = 0;
+        spin_lock_init(&ohci->AR_resp_lock);
+
+        /* initialize AR response receive task */
+        ohci->AR_resp_pdl_task.routine= ohci_ar_resp_proc_desc;
+        ohci->AR_resp_pdl_task.data= (void*)ohci;
+
 	/* AT dma program allocation */
 	ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE, 
 						      GFP_KERNEL);
@@ -1129,8 +1329,12 @@
 p += sprintf(p,fmt,reg_read(ohci, reg0),\
 	       reg_read(ohci, reg1),reg_read(ohci, reg2));
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+static int ohci_get_status(char *buf)
+#else
 int ohci_get_info(char *buf, char **start, off_t fpos, 
 		  int length, int dummy)
+#endif
 {
 	struct ti_ohci *ohci=&cards[0];
 	struct hpsb_host *host=ohci->host;
@@ -1165,15 +1369,23 @@
 		     host->is_irm ? "iso_res_mgr" : "",
 		     host->is_busmgr ? "bus_mgr" : "");
   
-	p += sprintf(p,"\n### ohci data ###\n");
-	p += sprintf(p,"AR_resp_buf : %p  AR_resp_prg: %p\n",
-		     ohci->AR_resp_buf, ohci->AR_resp_prg);
-
+	p += sprintf(p,"\n---Iso Receive DMA---\n");
         for (i= 0; i < IR_NUM_DESC; i++) {
                 p += sprintf(p, "IR_recv_buf[%d] : %p  IR_recv_prg[%d]: %p\n",
                              i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]);
 	}
 
+	
+	p += sprintf(p,"\n---Async Reponse Receive DMA---\n");
+        for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+                p += sprintf(p, "AR_resp_buf[%d] : %p  AR_resp_prg[%d]: %p\n",
+                             i, ohci->AR_resp_buf[i], i, ohci->AR_resp_prg[i]);
+	}
+	p += sprintf(p, "Current AR resp buf in irq handler: %d offset: %d\n",
+		     ohci->AR_resp_buf_th_ind,ohci->AR_resp_buf_th_offset);
+	p += sprintf(p, "Current AR resp buf in bottom half: %d offset: %d\n",
+		     ohci->AR_resp_buf_bh_ind,ohci->AR_resp_buf_bh_offset);
+	
 	/* ----- Register Dump ----- */
 	p += sprintf(p,"\n### HC Register dump ###\n");
 	SR("Version     : %08x  GUID_ROM    : %08x  ATRetries   : %08x\n",
@@ -1242,12 +1454,27 @@
 		     phyreg&0x3f);
 #endif
 
+#if 0
 	p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control);
 	p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status);
+#endif
 
 	return  p - buf;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+static int ohci1394_read_proc(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+        int len = ohci_get_status(page);
+        if (len <= off+count) *eof = 1;
+        *start = page + off;
+        len -= off;
+        if (len>count) len = count;
+        if (len<0) len = 0;
+        return len;
+}
+#else
 struct proc_dir_entry ohci_proc_entry = 
 {
 	0,			/* Inode number - dynamic */
@@ -1261,18 +1488,36 @@
 	ohci_get_info,		/* The read function for this file */
 	NULL
 }; 
-#endif
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_PROC_FS */
 
 static void remove_card(struct ti_ohci *ohci)
 {
 	if (ohci->registers) 
 	  iounmap(ohci->registers);
-	if (ohci->AR_resp_buf) 
-	  kfree(ohci->AR_resp_buf);
-	if (ohci->AR_resp_prg) 
-	  kfree(ohci->AR_resp_prg);
+
+	/* Free AR response buffers and programs */
+	if (ohci->AR_resp_buf) {
+		int i;
+                for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+			kfree(ohci->AR_resp_buf[i]);
+		}
+		kfree(ohci->AR_resp_buf);
+	}
+	if (ohci->AR_resp_prg) {
+		int i;
+		for (i= 0; i < AR_RESP_NUM_DESC; i++) {
+			kfree(ohci->AR_resp_prg[i]);
+		}
+		kfree(ohci->AR_resp_prg);
+	}
+	kfree(ohci->AR_resp_spb);
+
+	/* Free AT request buffer and program */
 	if (ohci->AT_req_prg) 
 	  kfree(ohci->AT_req_prg);
+
+	/* Free Iso receive buffers and programs */
 	if (ohci->IR_recv_buf) {
 		int i;
                 for (i= 0; i < IR_NUM_DESC; i++) {
@@ -1288,11 +1533,16 @@
 		kfree(ohci->IR_recv_prg);
 	}
 	kfree(ohci->IR_spb);
+
+	/* Free self-id buffer */
 	if (ohci->self_id_buffer)
 	  kfree(ohci->self_id_buffer);
+	
+	/* Free config rom */
 	if (ohci->csr_config_rom)
 	  kfree(ohci->csr_config_rom);
 
+	/* Free the IRQ */
 	free_irq(ohci->dev->irq, ohci);
 
 	ohci->state = 0;
@@ -1327,11 +1577,15 @@
 	}
 
 #ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL);
+#else
 	if (proc_register(&proc_root, &ohci_proc_entry)) {
 		PRINT_G(KERN_ERR, "unable to register proc file\n");
 		return -EIO;
 	}
 #endif
+#endif
 	return 0;
 }
 
@@ -1384,7 +1638,11 @@
 {
 	hpsb_unregister_lowlevel(get_ohci_template());
 #ifdef CONFIG_PROC_FS
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+	remove_proc_entry ("ohci1394", NULL);
+#else
 	proc_unregister(&proc_root, ohci_proc_entry.low_ino);
+#endif
 #endif
 	PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n");
 }
diff -u --recursive --new-file v2.3.41/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h
--- v2.3.41/linux/drivers/ieee1394/ohci1394.h	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/ohci1394.h	Mon Jan 31 10:13:03 2000
@@ -20,9 +20,15 @@
 
 #define MAX_OHCI1394_CARDS        4
 
-#define AR_RESP_BUF_SIZE          4096
-#define AR_RESP_PRG_SIZE          256
-#define AT_REQ_PRG_SIZE           256
+#define OHCI1394_MAX_AT_REQ_RETRIES       1
+#define OHCI1394_MAX_AT_RESP_RETRIES      1
+#define OHCI1394_MAX_PHYS_RESP_RETRIES    4
+
+#define AR_RESP_NUM_DESC                  4 /* number of AR resp descriptors */
+#define AR_RESP_BUF_SIZE               4096 /* size of AR resp buffers */
+#define AR_RESP_SPLIT_PACKET_BUF_SIZE   256 /* split packet buffer */
+#define AR_RESP_TOTAL_BUF_SIZE         (AR_RESP_BUF_SIZE * AR_RESP_NUM_DESC)
+#define AT_REQ_PRG_SIZE                256
 
 #define IR_RECV_BUF_SIZE          4096 /* 4096 bytes/buffer */
 #define IR_SPLIT_PACKET_BUF_SIZE  8192 /* size of buffer for split packets */
@@ -49,8 +55,18 @@
         quadlet_t *csr_config_rom; /* buffer for csr config rom */
 
         /* asynchronous receive */
-        struct dma_cmd *AR_resp_prg;
-        quadlet_t *AR_resp_buf;
+        struct dma_cmd **AR_resp_prg;
+        quadlet_t **AR_resp_buf;
+        unsigned int AR_resp_buf_bh_ind;
+        unsigned int AR_resp_buf_bh_offset;
+        unsigned int AR_resp_buf_th_ind;
+        unsigned int AR_resp_buf_th_offset;
+	int AR_resp_bytes_left;
+        quadlet_t *AR_resp_spb;
+        spinlock_t AR_resp_lock;
+
+        /* async receive task */
+        struct tq_struct AR_resp_pdl_task;
 
         /* asynchronous transmit */
         struct dma_cmd *AT_req_prg;
diff -u --recursive --new-file v2.3.41/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c
--- v2.3.41/linux/drivers/ieee1394/raw1394.c	Fri Jan 21 18:19:16 2000
+++ linux/drivers/ieee1394/raw1394.c	Mon Jan 31 10:13:03 2000
@@ -495,8 +495,8 @@
 
                 if (req->req.length == 8) {
                         req->req.error = highlevel_lock(fi->host, req->data,
-                                                        addr, req->data[0],
-                                                        req->data[1],
+                                                        addr, req->data[1],
+                                                        req->data[0],
                                                         req->req.misc);
                         req->req.length = 4;
                 } else {
@@ -567,6 +567,32 @@
                 break;
 
         case RAW1394_REQ_LOCK:
+                if ((req->req.misc != EXTCODE_FETCH_ADD)
+                    && (req->req.misc != EXTCODE_LITTLE_ADD)) {
+                        if (req->req.length != 4) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                } else {
+                        if (req->req.length != 8) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                }
+
+                packet = hpsb_make_lockpacket(fi->host, node, addr,
+                                              req->req.misc);
+                if (!packet) return -ENOMEM;
+
+                if (copy_from_user(packet->data, req->req.sendb,
+                                   req->req.length)) {
+                        req->req.error = RAW1394_ERROR_MEMFAULT;
+                        break;
+                }
+
+                req->req.length = 4;
+                break;
+
         case RAW1394_REQ_LOCK64:
         default:
                 req->req.error = RAW1394_ERROR_STATE_ORDER;
diff -u --recursive --new-file v2.3.41/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.41/linux/drivers/net/Makefile	Fri Jan 21 18:19:16 2000
+++ linux/drivers/net/Makefile	Mon Jan 31 10:34:12 2000
@@ -115,7 +115,7 @@
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_ETHERTAP) += ethertap.o
 obj-$(CONFIG_NET_SB1000) += sb1000.o
-obj-$(CONFIG_DAYNAPORT) += daynaport.o 8390.o
+obj-$(CONFIG_MAC8390) += daynaport.o 8390.o
 obj-$(CONFIG_APNE) += apne.o 8390.o
 obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
 obj-$(CONFIG_SHAPER) += shaper.o
@@ -247,6 +247,8 @@
 obj-$(CONFIG_RCPCI) += rcpci.o
 obj-$(CONFIG_MACE) += mace.o
 obj-$(CONFIG_MACSONIC) += macsonic.o
+obj-$(CONFIG_MACMACE) += macmace.o
+obj-$(CONFIG_MAC89x0) += mac89x0.o
 obj-$(CONFIG_BMAC) += bmac.o
 obj-$(CONFIG_NCR885E) += ncr885e.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
diff -u --recursive --new-file v2.3.41/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.41/linux/drivers/net/Space.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/Space.c	Mon Jan 31 10:34:12 2000
@@ -105,7 +105,13 @@
 extern int mvme147lance_probe(struct net_device *dev);
 extern int tc515_probe(struct net_device *dev);
 extern int lance_probe(struct net_device *dev);
-extern int mac_onboard_sonic_probe(struct net_device *dev);
+extern int mace68k_probe(struct net_device *dev);
+extern int macsonic_probe(struct net_device *dev);
+extern int mac8390_probe(struct net_device *dev);
+extern int mac89x0_probe(struct net_device *dev);
+  
+  /* Gigabit Ethernet adapters */
+  extern int yellowfin_probe(struct net_device *dev);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct net_device *);
@@ -355,8 +361,17 @@
 #ifdef CONFIG_MVME147_NET	/* MVME147 internal Ethernet */
 	{mvme147lance_probe, 0},
 #endif
-#ifdef CONFIG_MACSONIC		/* Mac 68k Quadra builtin Ethernet */ 
-	{mac_onboard_sonic_probe, 0},
+#ifdef CONFIG_MACMACE		/* Mac 68k Quadra AV builtin Ethernet */
+	{mace68k_probe, 0},
+#endif
+#ifdef CONFIG_MACSONIC		/* Mac SONIC-based Ethernet of all sorts */ 
+	{macsonic_probe, 0},
+#endif
+#ifdef CONFIG_MAC8390           /* NuBus NS8390-based cards */
+	{mac8390_probe, 0},
+#endif
+#ifdef CONFIG_MAC89x0
+ 	{mac89x0_probe, 0},
 #endif
 	{NULL, 0},
 };
diff -u --recursive --new-file v2.3.41/linux/drivers/net/cs89x0.h linux/drivers/net/cs89x0.h
--- v2.3.41/linux/drivers/net/cs89x0.h	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/cs89x0.h	Mon Jan 31 23:43:51 2000
@@ -14,6 +14,8 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    */
 
+#include <linux/config.h>
+
 #define PP_ChipID 0x0000	/* offset   0h -> Corp -ID              */
 				/* offset   2h -> Model/Product Number  */
 				/* offset   3h -> Chip Revision Number  */
@@ -76,6 +78,12 @@
 #define LAST_IO 0x037C		/*  Last I/O port to check (+10h) */
 #define ADD_MASK 0x3000		/*  Mask it use of the ADD_PORT register */
 #define ADD_SIG 0x3000		/*  Expected ID signature */
+
+/* On Macs, we only need use the ISA I/O stuff until we do MEMORY_ON */
+#ifdef CONFIG_MAC
+#define LCSLOTBASE 0xfee00000
+#define MMIOBASE 0x40000
+#endif
 
 #define CHIP_EISA_ID_SIG 0x630E   /*  Product ID Code for Crystal Chip (CS8900 spec 4.3) */
 
diff -u --recursive --new-file v2.3.41/linux/drivers/net/daynaport.c linux/drivers/net/daynaport.c
--- v2.3.41/linux/drivers/net/daynaport.c	Wed Aug 18 11:36:41 1999
+++ linux/drivers/net/daynaport.c	Mon Jan 31 10:34:12 2000
@@ -1,4 +1,4 @@
-/* mac_ns8390.c: A Macintosh 8390 based ethernet driver for linux. */
+/* daynaport.c: A Macintosh 8390 based ethernet driver for linux. */
 /*
 	Derived from code:
 	
@@ -15,14 +15,20 @@
 	    The block output routines may be wrong for non Dayna
 	    cards
 
-	    Reading MAC addresses
-*/
+		Fix this driver so that it will attempt to use the info
+		(i.e. iobase, iosize) given to it by the new and improved
+		NuBus code.
+
+		Despite its misleading filename, this driver is not Dayna-specific
+		anymore. */
+/* Cabletron E6100 card support added by Tony Mantler (eek@escape.ca) April 1999 */
 
 static const char *version =
-	"mac_ns8390.c:v0.01 7/5/97 Alan Cox (Alan.Cox@linux.org)\n";
+	"daynaport.c: v0.02 1999-05-17 Alan Cox (Alan.Cox@linux.org) and others\n";
+static int version_printed = 0;
 
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
@@ -31,20 +37,26 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/hwtest.h>
+#include <asm/macints.h>
 #include <linux/delay.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include "8390.h"
 
-int ns8390_probe1(struct net_device *dev, int word16, char *name, int id, int prom);
+extern int console_loglevel;
+
+int ns8390_probe1(struct net_device *dev, int word16, char *name, int id,
+				  int prom, struct nubus_dev *ndev);
 
 static int ns8390_open(struct net_device *dev);
 static void ns8390_no_reset(struct net_device *dev);
 static int ns8390_close_card(struct net_device *dev);
 
+/* Interlan */
 static void interlan_reset(struct net_device *dev);
 
+/* Dayna */
 static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void dayna_block_input(struct net_device *dev, int count,
@@ -52,6 +64,7 @@
 static void dayna_block_output(struct net_device *dev, int count,
 						   const unsigned char *buf, const int start_page);
 
+/* Sane (32-bit chunk memory read/write) */
 static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void sane_block_input(struct net_device *dev, int count,
@@ -59,6 +72,7 @@
 static void sane_block_output(struct net_device *dev, int count,
 						   const unsigned char *buf, const int start_page);
 
+/* Slow Sane (16-bit chunk memory read/write) */
 static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
 						int ring_page);
 static void slow_sane_block_input(struct net_device *dev, int count,
@@ -71,6 +85,10 @@
 #define WD03_STOP_PG	0x20	/* Last page +1 of RX ring */
 #define WD13_STOP_PG	0x40	/* Last page +1 of RX ring */
 
+#define CABLETRON_RX_START_PG          0x00    /* First page of RX buffer */
+#define CABLETRON_RX_STOP_PG           0x30    /* Last page +1 of RX ring */
+#define CABLETRON_TX_START_PG          CABLETRON_RX_STOP_PG  /* First page of TX buffer */
+
 
 #define DAYNA_MAC_BASE		0xf0007
 #define DAYNA_8390_BASE		0x80000 /* 3 */
@@ -81,9 +99,14 @@
 #define APPLE_8390_MEM		0xD0000
 #define APPLE_MEMSIZE		8192    /* FIXME: need to dynamically check */
 
-#define KINETICS_8390_BASE	0x80003
-#define KINETICS_8390_MEM	0x00000
+#define KINETICS_MAC_BASE	0xf0004 /* first byte of each long */
+#define KINETICS_8390_BASE	0x80000
+#define KINETICS_8390_MEM	0x00000 /* first word of each long */
 #define KINETICS_MEMSIZE	8192    /* FIXME: need to dynamically check */
+/*#define KINETICS_MEMSIZE	(0x10000/2) * CSA: on the board I have, at least */
+
+#define CABLETRON_8390_BASE		0x90000	
+#define CABLETRON_8390_MEM		0x00000
 
 static int test_8390(volatile char *ptr, int scale)
 {
@@ -113,34 +136,59 @@
  *    Identify the species of NS8390 card/driver we need
  */
 
-#define NS8390_DAYNA		1
-#define NS8390_INTERLAN		2
-#define NS8390_KINETICS		3
-#define NS8390_APPLE		4
-#define NS8390_FARALLON		5
-#define NS8390_ASANTE		6
-
-int ns8390_ident(struct nubus_type *nb)
-{
-	/* It appears anything with a software type of 0 is an apple
-	   compatible - even if the hardware matches others */
-	   
-	if(nb->DrSW==0x0001 || nb->DrSW==0x0109 || nb->DrSW==0x0000 || nb->DrSW==0x0100)
-		return NS8390_APPLE;
-	
+enum mac8390_type {
+	NS8390_DAYNA,
+	NS8390_INTERLAN,
+	NS8390_KINETICS,
+	NS8390_APPLE,
+	NS8390_FARALLON,
+	NS8390_ASANTE,
+	NS8390_CABLETRON
+};
+
+int __init ns8390_ident(struct nubus_dev* ndev)
+{
+	/* This really needs to be tested and tested hard.  */
+		
+	/* Summary of what we know so far --
+	 * SW: 0x0104 -- asante,    16 bit, back4_offsets
+	 * SW: 0x010b -- daynaport, 16 bit, fwrd4_offsets
+	 * SW: 0x010c -- farallon,  16 bit, back4_offsets, no long word access
+	 * SW: 0x011a -- focus,     [no details yet]
+	 * SW: ?????? -- interlan,  16 bit, back4_offsets, funny reset
+	 * SW: ?????? -- kinetics,   8 bit, back4_offsets
+	 * -- so i've this hypothesis going that says DrSW&1 says whether the
+	 *    map is forward or backwards -- and maybe DrSW&256 says what the
+	 *    register spacing is -- for all cards that report a DrSW in some
+	 *    range.
+	 *    This would allow the "apple compatible" driver to drive many
+	 *    seemingly different types of cards.  More DrSW info is needed
+	 *    to investigate this properly. [CSA, 21-May-1999]
+	 */
 	/* Dayna ex Kinetics board */
-	if(nb->DrHW==0x0103)
+	if(ndev->dr_sw == NUBUS_DRSW_DAYNA)
 		return NS8390_DAYNA;
-
-	/* Asante board */
-	if(nb->DrHW==0x0104)
+	if(ndev->dr_sw == NUBUS_DRSW_ASANTE)
 		return NS8390_ASANTE;
-	if(nb->DrHW==0x0100)
-		return NS8390_INTERLAN;
-	if(nb->DrHW==0x0106)
-		return NS8390_KINETICS;
-	if(nb->DrSW==0x010C)
+	if(ndev->dr_sw == NUBUS_DRSW_FARALLON) /* farallon or sonic systems */
 		return NS8390_FARALLON;
+	if(ndev->dr_sw == NUBUS_DRSW_KINETICS)
+		return NS8390_KINETICS;
+	/* My ATI Engineering card with this combination crashes the */
+	/* driver trying to xmit packets. Best not touch it for now. */
+	/*     - 1999-05-20 (funaho@jurai.org)                       */
+	if(ndev->dr_sw == NUBUS_DRSW_FOCUS)
+		return -1;
+
+	/* Check the HW on this one, because it shares the same DrSW as
+	   the on-board SONIC chips */
+	if(ndev->dr_hw == NUBUS_DRHW_CABLETRON)
+		return NS8390_CABLETRON;
+	/* does anyone have one of these? */
+	if(ndev->dr_hw == NUBUS_DRHW_INTERLAN)
+		return NS8390_INTERLAN;
+
+	/* FIXME: what do genuine Apple boards look like? */
 	return -1;
 }
 
@@ -148,7 +196,7 @@
  *	Memory probe for 8390 cards
  */
  
-int apple_8390_mem_probe(volatile unsigned short *p)
+int __init apple_8390_mem_probe(volatile unsigned short *p)
 {
 	int i, j;
 	/*
@@ -192,61 +240,79 @@
 /*
  *    Probe for 8390 cards.  
  *    The ns8390_probe1() routine initializes the card and fills the
- *    station address field. On entry base_addr is set, irq is set
- *    (These come from the nubus probe code). dev->mem_start points
+ *    station address field.
+ *
+ *    The NuBus interface has changed!  We now scan for these somewhat
+ *    like how the PCI and Zorro drivers do.  It's not clear whether
+ *    this is actually better, but it makes things more consistent.
+ *
+ *    dev->mem_start points
  *    at the memory ring, dev->mem_end gives the end of it.
  */
 
-int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *match)
+int __init mac8390_probe(struct net_device *dev)
 {
-	struct net_device *dev;
+	static int slots = 0;
 	volatile unsigned short *i;
 	volatile unsigned char *p;
 	int plen;
 	int id;
+	static struct nubus_dev* ndev = NULL;
 
-	if(match->category!=NUBUS_CAT_NETWORK || match->type!=1)
-		return -ENODEV;		
-	/* Ok so it is an ethernet network device */
-	if((id=ns8390_ident(match))==-1)
-	{
-		printk("Ethernet but type unknown %d\n",match->DrHW);
+	/* Find the first card that hasn't already been seen */
+	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
+								   NUBUS_TYPE_ETHERNET, ndev)) != NULL) {
+		/* Have we seen it already? */
+		if (slots & (1<<ndev->board->slot))
+			continue;
+		slots |= 1<<ndev->board->slot;
+
+		/* Is it one of ours? */
+		if ((id = ns8390_ident(ndev)) != -1)
+			break;
+	}
+
+	/* Hm.  No more cards, then */
+	if (ndev == NULL)
 		return -ENODEV;
+
+	dev = init_etherdev(dev, 0);
+
+	if (!version_printed) {
+		printk(KERN_INFO "%s", version);
+		version_printed = 1;
 	}
-	dev = init_etherdev(0, 0);
-	if(dev==NULL)
-		return -ENOMEM;
 
 	/*
 	 *	Dayna specific init
 	 */
 	if(id==NS8390_DAYNA)
 	{
-		dev->base_addr=(int)(nubus_slot_addr(slot)+DAYNA_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+DAYNA_8390_MEM);
-		dev->mem_end=dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
+		dev->base_addr = (int)(ndev->board->slot_addr+DAYNA_8390_BASE);
+		dev->mem_start = (int)(ndev->board->slot_addr+DAYNA_8390_MEM);
+		dev->mem_end = dev->mem_start+DAYNA_MEMSIZE; /* 8K it seems */
 	
-		printk("daynaport: testing board: ");
-
+		printk(KERN_INFO "%s: daynaport. testing board: ", dev->name);
+			
 		printk("memory - ");	
-	
-		i=(void *)dev->mem_start;
+			
+		i = (void *)dev->mem_start;
 		memset((void *)i,0xAA, DAYNA_MEMSIZE);
 		while(i<(volatile unsigned short *)dev->mem_end)
 		{
 			if(*i!=0xAAAA)
 				goto membad;
-			*i=0x5555;
-			if(*i!=0x5555)
+			*i=0x5678; /* make sure we catch byte smearing */
+			if(*i!=0x5678)
 				goto membad;
 			i+=2;	/* Skip a word */
 		}
-
+			
 		printk("controller - ");
-	
+			
 		p=(void *)dev->base_addr;
 		plen=0;
-	
+			
 		while(plen<0x3FF00)
 		{
 			if(test_8390(p,0)==0)
@@ -263,26 +329,71 @@
 		if(plen==0x3FF00)
 			goto membad;
 		printk("OK\n");
-		dev->irq=slot;
-		if(ns8390_probe1(dev, 0, "dayna", id, -1)==0)
-		return 0;
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		if(ns8390_probe1(dev, 0, "dayna", id, -1, ndev)==0)
+			return 0;
+	}
+	/* Cabletron */
+	if (id==NS8390_CABLETRON) {
+		int memsize = 16<<10; /* fix this */
+		  
+		dev->base_addr=(int)(ndev->board->slot_addr+CABLETRON_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+CABLETRON_8390_MEM);
+		dev->mem_end=dev->mem_start+memsize;
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		  
+		/* The base address is unreadable if 0x00 has been written to the command register */
+		/* Reset the chip by writing E8390_NODMA+E8390_PAGE0+E8390_STOP just to be sure */
+		i = (void *)dev->base_addr;
+		*i = 0x21;
+		  
+		printk(KERN_INFO "%s: cabletron: testing board: ", dev->name);
+		printk("%dK memory - ", memsize>>10);		
+		i=(void *)dev->mem_start;
+		while(i<(volatile unsigned short *)(dev->mem_start+memsize))
+		{
+			*i=0xAAAA;
+			if(*i!=0xAAAA)
+				goto membad;
+			*i=0x5555;
+			if(*i!=0x5555)
+				goto membad;
+			i+=2;	/* Skip a word */
+		}
+		printk("OK\n");
+		  
+		if(ns8390_probe1(dev, 1, "cabletron", id, -1, ndev)==0)
+			return 0;
 	}
 	/* Apple, Farallon, Asante */
-	if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
+	if(id==NS8390_APPLE || id==NS8390_FARALLON || id==NS8390_ASANTE)
 	{
 		int memsize;
-		
-		dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
-		
+			
+		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
+			
 		memsize = apple_8390_mem_probe((void *)dev->mem_start);
-		
+			
 		dev->mem_end=dev->mem_start+memsize;
-		dev->irq=slot;
-		printk("apple/clone: testing board: ");
-
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+			
+		switch(id)
+		{
+		case NS8390_FARALLON:
+			printk(KERN_INFO "%s: farallon: testing board: ", dev->name);
+			break;
+		case NS8390_ASANTE:
+			printk(KERN_INFO "%s: asante: testing board: ", dev->name);
+			break;
+		case NS8390_APPLE:
+		default:
+			printk(KERN_INFO "%s: apple/clone: testing board: ", dev->name);
+			break;
+		}
+			
 		printk("%dK memory - ", memsize>>10);		
-
+			
 		i=(void *)dev->mem_start;
 		memset((void *)i,0xAA, memsize);
 		while(i<(volatile unsigned short *)dev->mem_end)
@@ -295,51 +406,75 @@
 			i+=2;	/* Skip a word */
 		}
 		printk("OK\n");
-
-		if(id==NS8390_FARALLON)
+			
+		switch (id)
 		{
-			if(ns8390_probe1(dev, 1, "farallon", id, -1)==0)
+		case NS8390_FARALLON:
+			if(ns8390_probe1(dev, 1, "farallon", id, -1, ndev)==0)
 				return 0;
-		}
-		else
-		{
-			if(ns8390_probe1(dev, 1, "apple/clone", id, -1)==0)
-			    return 0;
+			break;
+		case NS8390_ASANTE:
+			if(ns8390_probe1(dev, 1, "asante", id, -1, ndev)==0)
+				return 0;
+			break;
+		case NS8390_APPLE:
+		default:
+			if(ns8390_probe1(dev, 1, "apple/clone", id, -1, ndev)==0)
+				return 0;
+			break;
 		}
 	}
 	/* Interlan */
 	if(id==NS8390_INTERLAN)
 	{
 		/* As apple and asante */
-		dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
+		dev->base_addr=(int)(ndev->board->slot_addr+APPLE_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+APPLE_8390_MEM);
 		dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
-		dev->irq=slot;
-		if(ns8390_probe1(dev, 1, "interlan", id, -1)==0)
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		if(ns8390_probe1(dev, 1, "interlan", id, -1, ndev)==0)
 			return 0;
 	}
-	/* Kinetics */
+	/* Kinetics (Shiva Etherport) */
 	if(id==NS8390_KINETICS)
 	{
-		dev->base_addr=(int)(nubus_slot_addr(slot)+KINETICS_8390_BASE);
-		dev->mem_start=(int)(nubus_slot_addr(slot)+KINETICS_8390_MEM);
+		dev->base_addr=(int)(ndev->board->slot_addr+KINETICS_8390_BASE);
+		dev->mem_start=(int)(ndev->board->slot_addr+KINETICS_8390_MEM);
 		dev->mem_end=dev->mem_start+KINETICS_MEMSIZE; /* 8K it seems */
-		dev->irq=slot;
-		if(ns8390_probe1(dev, 0, "kinetics", id, -1)==0)
+		dev->irq = SLOT2IRQ(ndev->board->slot);
+		if(ns8390_probe1(dev, 0, "kinetics", id, -1, ndev)==0)
 			return 0;
 	}
-	kfree(dev);
+
+	/* We should hopefully not get here */
+	printk(KERN_ERR "Probe unsucessful.\n");
 	return -ENODEV;
-membad:
-	printk("failed.\n");
-	kfree(dev);
+
+ membad:
+	printk(KERN_ERR "failed at %p in %p - %p.\n", i,
+		   (void *)dev->mem_start, (void *)dev->mem_end);
 	return -ENODEV;
 }
 
-int ns8390_probe1(struct net_device *dev, int word16, char *model_name, int type, int promoff)
+int __init mac8390_ethernet_addr(struct nubus_dev* ndev, 
+				 unsigned char addr[6])
 {
-	static unsigned version_printed = 0;
+	struct nubus_dir dir;
+	struct nubus_dirent ent;
+
+	/* Get the functional resource for this device */
+	if (nubus_get_func_dir(ndev, &dir) == -1)
+		return -1;
+	if (nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent) == -1)
+		return -1;
+	
+	nubus_get_rsrc_mem(addr, &ent, 6);
+	return 0;
+}
 
+int __init ns8390_probe1(struct net_device *dev, int word16, char *model_name,
+			 int type, int promoff, struct nubus_dev *ndev)
+{
 	static u32 fwrd4_offsets[16]={
 		0,      4,      8,      12,
 		16,     20,     24,     28,
@@ -352,25 +487,19 @@
 		28,     24,     20,     16,
 		12,     8,      4,      0
 	};
+	static u32 fwrd2_offsets[16]={
+		0,      2,      4,      6,
+		8,     10,     12,     14,
+		16,    18,     20,     22,
+		24,    26,     28,     30
+	};
 
-	unsigned char *prom=((unsigned char *)nubus_slot_addr(dev->irq))+promoff;
+	unsigned char *prom = (unsigned char*) ndev->board->slot_addr + promoff;
 
-	if (ei_debug  &&  version_printed++ == 0)
-		printk(version);
-	
-	/* Snarf the interrupt now.  There's no point in waiting since we cannot
-	   share a slot! and the board will usually be enabled. */
-	if (nubus_request_irq(dev->irq, dev, ei_interrupt)) 
-	{
-		printk (" unable to get nubus IRQ %d.\n", dev->irq);
-		return EAGAIN;
-	}
-	
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (ethdev_init(dev)) 
 	{	
-		printk (" unable to get memory for dev->priv.\n");
-		nubus_free_irq(dev->irq);
+		printk ("%s: unable to get memory for dev->priv.\n", dev->name);
 		return -ENOMEM;
 	}
 
@@ -378,16 +507,25 @@
 
 	ei_status.name = model_name;
 	ei_status.word16 = word16;
-	ei_status.tx_start_page = WD_START_PG;
-	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
-	ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-	dev->rmem_end = dev->mem_end;
+       if (type==NS8390_CABLETRON) {
+               /* Cabletron card puts the RX buffer before the TX buffer */
+               ei_status.tx_start_page = CABLETRON_TX_START_PG;
+               ei_status.rx_start_page = CABLETRON_RX_START_PG;
+               ei_status.stop_page = CABLETRON_RX_STOP_PG;
+               dev->rmem_start = dev->mem_start;
+               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+       } else {
+               ei_status.tx_start_page = WD_START_PG;
+               ei_status.rx_start_page = WD_START_PG + TX_PAGES;
+               ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
+               dev->rmem_start = dev->mem_start + TX_PAGES*256;
+               dev->rmem_end = dev->mem_end;
+       }
 	
 	if(promoff==-1)		/* Use nubus resources ? */
 	{
-		if(nubus_ethernet_addr(dev->irq /* slot */, dev->dev_addr))
+		if(mac8390_ethernet_addr(ndev, dev->dev_addr))
 		{
 		  printk("mac_ns8390: MAC address not in resources!\n");
 		  return -ENODEV;
@@ -400,7 +538,7 @@
 		/* These should go in the end I hope */
 		if(type==NS8390_DAYNA)
 			x=2;
-		if(type==NS8390_INTERLAN)
+		if(type==NS8390_INTERLAN || type==NS8390_KINETICS)
 			x=4;
 		while(i<6)
 		{
@@ -412,12 +550,24 @@
 		}
 	}
 
-	printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
-		   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
+	printk(KERN_INFO "%s: %s in slot %X (type %s)\n",
+		   dev->name, ndev->board->name, ndev->board->slot, model_name);
+	printk(KERN_INFO "MAC ");
+	{
+		int i;
+		for (i = 0; i < 6; i++) {
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+	}
+	printk(" IRQ %d, shared memory at %#lx-%#lx.\n",
+		   dev->irq, dev->mem_start, dev->mem_end-1);
 
 	switch(type)
 	{
 		case NS8390_DAYNA:      /* Dayna card */
+		case NS8390_KINETICS:   /* Kinetics --  8 bit config, but 16 bit mem */
 			/* 16 bit, 4 word offsets */
 			ei_status.reset_8390 = &ns8390_no_reset;
 			ei_status.block_input = &dayna_block_input;
@@ -425,6 +575,15 @@
 			ei_status.get_8390_hdr = &dayna_get_8390_hdr;
 			ei_status.reg_offset = fwrd4_offsets;
 			break;
+		case NS8390_CABLETRON: /* Cabletron */
+			/*		16 bit card, register map is short forward */
+			ei_status.reset_8390 = &ns8390_no_reset;
+			/* Ctron card won't accept 32bit values read or written to it */
+			ei_status.block_input = &slow_sane_block_input;
+			ei_status.block_output = &slow_sane_block_output;
+			ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+			ei_status.reg_offset = fwrd2_offsets;
+			break;
 		case NS8390_FARALLON:
 		case NS8390_APPLE:	/* Apple/Asante/Farallon */
 			/*      16 bit card, register map is reversed */
@@ -450,6 +609,8 @@
 			ei_status.get_8390_hdr = &sane_get_8390_hdr;
 			ei_status.reg_offset = back4_offsets;
 			break;
+#if 0 /* i think this suffered code rot.  my kinetics card has much
+	   * different settings.  -- CSA [22-May-1999] */
 		case NS8390_KINETICS:   /* Kinetics */
 			/*      8bit card, map is forward */
 			ei_status.reset_8390 = &ns8390_no_reset;
@@ -458,6 +619,7 @@
 			ei_status.get_8390_hdr = &sane_get_8390_hdr;
 			ei_status.reg_offset = back4_offsets;
 			break;
+#endif
 		default:
 			panic("Detected a card I can't drive - whoops\n");
 	}
@@ -472,6 +634,19 @@
 static int ns8390_open(struct net_device *dev)
 {
 	ei_open(dev);
+
+	/* At least on my card (a Focus Enhancements PDS card) I start */
+	/* getting interrupts right away, so the driver needs to be    */
+	/* completely initialized before enabling the interrupt.        */
+	/*                             - funaho@jurai.org (1999-05-17) */
+
+	/* Non-slow interrupt, works around issues with the SONIC driver */
+	if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) 
+	{
+		printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return EAGAIN;
+	}
+	
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -489,24 +664,19 @@
 {
 	if (ei_debug > 1)
 		printk("%s: Shutting down ethercard.\n", dev->name);
+	free_irq(dev->irq, dev);
 	ei_close(dev);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-struct nubus_device_specifier nubus_8390={
-	ns8390_probe,
-	NULL
-};
-
-
 /*
  *    Interlan Specific Code Starts Here
  */
 
 static void interlan_reset(struct net_device *dev)
 {
-	unsigned char *target=nubus_slot_addr(dev->irq);
+	unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
 	if (ei_debug > 1) 
 		printk("Need to reset the NS8390 t=%lu...", jiffies);
 	ei_status.txing = 0;
@@ -531,16 +701,23 @@
    The only complications are that the ring buffer wraps.
 */
 
-static void dayna_cpu_memcpy(struct net_device *dev, void *to, int from, int count)
+static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
 {
 	volatile unsigned short *ptr;
 	unsigned short *target=to;
 	from<<=1;	/* word, skip overhead */
 	ptr=(unsigned short *)(dev->mem_start+from);
+	/*
+	 * Leading byte?
+	 */
+	if (from&2) {
+		*((char *)target)++ = *(((char *)ptr++)-1);
+		count--;
+	}
 	while(count>=2)
 	{
 		*target++=*ptr++;	/* Copy and */
-		ptr++;			/* Cruft and */
+		ptr++;			/* skip cruft */
 		count-=2;
 	}
 	/*
@@ -554,16 +731,24 @@
 	}
 }
 
-static void cpu_dayna_memcpy(struct net_device *dev, int to, const void *from, int count)
+static void dayna_memcpy_tocard(struct net_device *dev, int to, const void *from, int count)
 {
 	volatile unsigned short *ptr;
 	const unsigned short *src=from;
 	to<<=1;	/* word, skip overhead */
 	ptr=(unsigned short *)(dev->mem_start+to);
+	/*
+	 * Leading byte?
+	 */
+	if (to&2) { /* avoid a byte write (stomps on other data) */
+		ptr[-1] = (ptr[-1]&0xFF00)|*((unsigned char *)src)++;
+		ptr++;
+		count--;
+	}
 	while(count>=2)
 	{
 		*ptr++=*src++;		/* Copy and */
-		ptr++;			/* Cruft and */
+		ptr++;			/* skip cruft */
 		count-=2;
 	}
 	/*
@@ -573,14 +758,15 @@
 	{
 		/* Big endian */
 		unsigned short v=*src;
-		*((char *)ptr)=v>>8;
+		/* card doesn't like byte writes */
+		*ptr=(*ptr&0x00FF)|(v&0xFF00);
 	}
 }
 
 static void dayna_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
 	unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
-	dayna_cpu_memcpy(dev, (void *)hdr, hdr_start, 4);
+	dayna_memcpy_fromcard(dev, (void *)hdr, hdr_start, 4);
 	/* Register endianism - fix here rather than 8390.c */
 	hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
 }
@@ -599,14 +785,14 @@
 	{
 		/* We must wrap the input move. */
 		int semi_count = dev->rmem_end - xfer_start;
-		dayna_cpu_memcpy(dev, skb->data, xfer_base, semi_count);
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
 		count -= semi_count;
-		dayna_cpu_memcpy(dev, skb->data + semi_count, 
+		dayna_memcpy_fromcard(dev, skb->data + semi_count, 
 			dev->rmem_start - dev->mem_start, count);
 	}
 	else
 	{
-		dayna_cpu_memcpy(dev, skb->data, xfer_base, count);
+		dayna_memcpy_fromcard(dev, skb->data, xfer_base, count);
 	}
 }
 
@@ -615,7 +801,7 @@
 {
 	long shmem = (start_page - WD_START_PG)<<8;
 	
-	cpu_dayna_memcpy(dev, shmem, buf, count);
+	dayna_memcpy_tocard(dev, shmem, buf, count);
 }
 
 /*
@@ -739,6 +925,7 @@
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
  *  version-control: t
+ *  c-basic-offset: 4
  *  tab-width: 4
  *  kept-new-versions: 5
  * End:
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in
--- v2.3.41/linux/drivers/net/irda/Config.in	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/Config.in	Fri Jan 28 19:36:22 2000
@@ -6,10 +6,12 @@
 dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA
 
 comment 'FIR device drivers'
-dep_tristate 'NSC PC87108/PC97338' CONFIG_NSC_FIR  $CONFIG_IRDA
+dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR  $CONFIG_IRDA
 dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
 dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
-dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
+fi
 
 comment 'Dongle support' 
 bool 'Serial dongle support' CONFIG_DONGLE
@@ -19,9 +21,7 @@
    dep_tristate '  Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA
    dep_tristate '  Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
    dep_tristate '  Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
-   dep_tristate '  Adaptec Airport 1000/2000 dongle' CONFIG_AIRPORT_DONGLE $CONFIG_IRDA
-   dep_tristate '  Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA
-   
+   dep_tristate '  Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA   
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile
--- v2.3.41/linux/drivers/net/irda/Makefile	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/Makefile	Fri Jan 28 19:36:22 2000
@@ -29,10 +29,10 @@
 endif
 
 ifeq ($(CONFIG_NSC_FIR),y)
-L_OBJS += nsc_fir.o
+L_OBJS += nsc-ircc.o
 else
   ifeq ($(CONFIG_NSC_FIR),m)
-  M_OBJS += nsc_fir.o
+  M_OBJS += nsc-ircc.o
   endif
 endif
 
@@ -115,14 +115,6 @@
 else
   ifeq ($(CONFIG_LITELINK_DONGLE),m)
   M_OBJS += litelink.o
-  endif
-endif
-
-ifeq ($(CONFIG_AIRPORT_DONGLE),y)
-L_OBJS += airport.o
-else
-  ifeq ($(CONFIG_AIRPORT_DONGLE),m)
-  M_OBJS += airport.o
   endif
 endif
 
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/airport.c linux/drivers/net/irda/airport.c
--- v2.3.41/linux/drivers/net/irda/airport.c	Wed Dec 29 13:13:16 1999
+++ linux/drivers/net/irda/airport.c	Wed Dec 31 16:00:00 1969
@@ -1,358 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      airport.c
- * Version:       0.2
- * Description:   Implementation for the Adaptec Airport 1000 and 2000 
- *                dongles
- * Status:        Experimental.
- * Author:        Fons Botman <budely@tref.nl>
- * Created at:    Wed May 19 23:14:34 CEST 1999
- * Based on:      actisys.c by Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-1999 Fons Botman, All Rights Reserved.
- *      
- *     This program is free software; you can redistribute it and/or 
- *     modify it under the terms of the GNU General Public License as 
- *     published by the Free Software Foundation; either version 2 of 
- *     the License, or (at your option) any later version.
- *  
- *     Neither Fons Botman nor anyone else admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/irda_device.h>
-
-static int  airport_reset_wrapper(struct irda_task *task);
-static void airport_open(dongle_t *self, struct qos_info *qos);
-static void airport_close(dongle_t *self);
-static int  airport_change_speed_wrapper(struct irda_task *task);
-
-static struct dongle_reg dongle = {
-	Q_NULL,
-	IRDA_AIRPORT_DONGLE,
-	airport_open,
-	airport_close,
-	airport_reset_wrapper,
-	airport_change_speed_wrapper,
-};
-
-int __init airport_init(void)
-{
-	int ret;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-	ret = irda_device_register_dongle(&dongle);
-	if (ret < 0)
-		return ret;
-	return 0;
-}
-
-void airport_cleanup(void)
-{
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-	irda_device_unregister_dongle(&dongle);
-}
-
-static void airport_open(dongle_t *self, struct qos_info *qos)
-{
-	qos->baud_rate.bits &= 
-		IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-	/* May need 1ms */
-	qos->min_turn_time.bits = 0x07;
-
-	MOD_INC_USE_COUNT;
-}
-
-static void airport_close(dongle_t *self)
-{
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-	/* Power off dongle */
-	self->set_dtr_rts(self->dev, FALSE, FALSE);
-
-	MOD_DEC_USE_COUNT;
-}
-
-static void airport_set_command_mode(dongle_t *self)
-{
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-	self->set_dtr_rts(self->dev, FALSE, TRUE);
-}
-
-static void airport_set_normal_mode(dongle_t *self)
-{
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-    	self->set_dtr_rts(self->dev, TRUE, TRUE);
-}
-
-void airport_write_char(dongle_t *self, unsigned char c)
-{
-	int actual;
-	IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c & 0xff);
-	actual = self->write(self->dev, &c, 1);
-	ASSERT(actual == 1, return;);
-}
-
-#define JIFFIES_TO_MSECS(j) ((j)*1000/HZ)
-
-static int airport_waitfor_char(dongle_t *self, unsigned char c)
-{
-	__u8 buf[100];
-	int i, found = FALSE;
-	int before;
-	int len;
-
-	IRDA_DEBUG(2, __FUNCTION__ "(,0x%x)\n", c);
-
-	/* Sleep approx. 10 ms */
-	before = jiffies;
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(20));
-	IRDA_DEBUG(4, __FUNCTION__ " waited %ldms\n", 
-	      JIFFIES_TO_MSECS(jiffies - before));
-
-	len = self->read(self->dev, buf, 100);
-
-	for (i = 0; !found && i < len; i++ ) {
-		/* IRDA_DEBUG(6, __FUNCTION__ " 0x02x\n", idev->rx_buff.data[i]); */
-		found = c == buf[i];
-	}
-
-	IRDA_DEBUG(2, __FUNCTION__ " returns %s\n", (found ? "true" : "false"));
-	return found;
-}
-
-static int airport_check_command_mode(dongle_t *self)
-{
-	int i;
-	int found = FALSE;
-  
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(20));
-	airport_set_command_mode(self);
-
-	/* Loop until the time expires (200ms) or we get the magic char. */
-
-	for ( i = 0 ; i < 25 ; i++ ) {
-	  	airport_write_char(self, 0xff);
-		if (airport_waitfor_char(self, 0xc3)) {
-			found = TRUE;
-			break;
-		}
-	}
-
-	if (found) {
-		IRDA_DEBUG(2, __FUNCTION__ " OK. (%d)\n", i);
-	} else {
-		IRDA_DEBUG(0, __FUNCTION__ " FAILED!\n");
-	}
-	return found;
-}
-
-static int airport_write_register(dongle_t *self, unsigned char reg)
-{
-	int ok = FALSE;
-	int i;
-
-	IRDA_DEBUG(4, __FUNCTION__ "(,0x%x)\n", reg);
-	airport_check_command_mode(self);
-
-	for ( i = 0 ; i < 6 ; i++ ) {
-		airport_write_char(self, reg);
-		if (!airport_waitfor_char(self, reg)) 
-			continue;
-
-		/* Now read it back */
-		airport_write_char(self, (reg << 4) | 0x0f);
-		if (airport_waitfor_char(self, reg)) {
-			ok = TRUE;
-			break;
-		}
-	}
-
-	airport_set_normal_mode(self);
-	if (ok) {
-		IRDA_DEBUG(4, __FUNCTION__ "(,0x%x) returns OK\n", reg);
-	} else {
-		IRDA_DEBUG(0, __FUNCTION__ "(,0x%x) returns False!\n", reg);
-	}
-	return ok;
-}
-
-
-/*
- * Function airport_change_speed (self, speed)
- *
- *    Change speed of the Airport type IrDA dongles.
- */
-static void airport_change_speed(dongle_t *self, __u32 speed)
-{
-        __u32 current_baudrate;
-        int baudcode;
-	
-	IRDA_DEBUG(4, __FUNCTION__ "(,%d)\n", speed);
-
-	ASSERT(self != NULL, return;);
-	
-	/* Find the correct baudrate code for the required baudrate */
-	switch (speed) {
-	case 2400:	baudcode = 0x10;	break;
-	case 4800:	baudcode = 0x20;	break;
-	case 9600:	baudcode = 0x30;	break;
-	case 19200:	baudcode = 0x40;	break;
-	case 38400:	baudcode = 0x50;	break;
-	case 57600:	baudcode = 0x60;	break;
-	case 115200:	baudcode = 0x70;	break;
-	default:
-		IRDA_DEBUG(0, __FUNCTION__ " bad baud rate: %d\n", speed);
-		return;
-	}
-
-	current_baudrate = self->speed;
-	IRDA_DEBUG(4, __FUNCTION__ " current baudrate: %d\n", current_baudrate);
-
-	self->set_mode(self->dev, IRDA_RAW);
-
-	/* Set the new speed in both registers */
-	if (airport_write_register(self, baudcode)) {
-		if (airport_write_register(self, baudcode|0x01)) {
-			/* ok */
-		} else {
-			IRDA_DEBUG(0, __FUNCTION__ 
-			      " Cannot set new speed in second register\n");
-		}
-	} else {
-		IRDA_DEBUG(0, __FUNCTION__ 
-		      " Cannot set new speed in first register\n");
-	}
-	
-	self->set_mode(self->dev, IRDA_IRLAP);
-
-	/* How do I signal an error in these functions? */
-
-	IRDA_DEBUG(4, __FUNCTION__ " returning\n");
-}
-
-int airport_change_speed_wrapper(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-	__u32 speed = (__u32) task->param;
-
-	irda_execute_as_process(self, (TODO_CALLBACK) airport_change_speed, 
-				speed);
-
-	irda_task_next_state(task, IRDA_TASK_DONE);
-	
-	return 0;
-}
-
-/*
- * Function airport_reset (self)
- *
- *      Reset the Airport type dongle. Warning, this function must only be
- *      called with a process context!
- *
- */
-static void airport_reset(dongle_t *self)
-{
-	int ok;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-	ASSERT(self != NULL, return;);
-
-	self->set_mode(self->dev, IRDA_RAW);
-
-	airport_set_normal_mode(self);
-
-	/* Sleep 2000 ms */
-	IRDA_DEBUG(2, __FUNCTION__ " waiting for powerup\n");
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(2000));
-	IRDA_DEBUG(2, __FUNCTION__ " finished waiting for powerup\n");
-	
-	/* set dongle speed to 9600 */
-	ok = TRUE;
-
-	if (ok)
-		ok = airport_write_register(self, 0x30);
-	if (!ok)
-		MESSAGE(__FUNCTION__ "() dongle not connected?\n");
-	if (ok)
-		ok = airport_write_register(self, 0x31);
-
-	if (ok)
-		ok = airport_write_register(self, 0x02);
-	if (ok)
-		ok = airport_write_register(self, 0x03);
-
-	if (ok) {
-		ok = airport_check_command_mode(self);
-
-		if (ok) {
-			airport_write_char(self, 0x04);
-			ok = airport_waitfor_char(self, 0x04);
-		}
-		airport_set_normal_mode(self);
-	}
-		
-	self->set_mode(self->dev, IRDA_IRLAP);
-	
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(MSECS_TO_JIFFIES(20));
-	IRDA_DEBUG(4, __FUNCTION__ " waited 20ms\n");
-
-	self->speed = 9600;
-	if (!ok)
-		MESSAGE(__FUNCTION__ "() failed.\n");
-	IRDA_DEBUG(2, __FUNCTION__ " returning.\n");
-}
-
-int airport_reset_wrapper(struct irda_task *task)
-{
-	dongle_t *self = (dongle_t *) task->instance;
-
-	irda_execute_as_process(self, (TODO_CALLBACK) airport_reset, 0);
-
-	irda_task_next_state(task, IRDA_TASK_DONE);
-	
-	return 0;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Fons Botman <budely@tref.nl>");
-MODULE_DESCRIPTION("Adaptec Airport 1000 and 2000 dongle driver");	
-		
-/*
- * Function init_module (void)
- *
- *    Initialize Airport module
- *
- */
-int init_module(void)
-{
-	return airport_init();
-}
-
-/*
- * Function cleanup_module (void)
- *
- *    Cleanup Airport module
- *
- */
-void cleanup_module(void)
-{
-	airport_cleanup();
-}
-
-#endif
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- v2.3.41/linux/drivers/net/irda/irport.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/irport.c	Fri Jan 28 19:36:22 2000
@@ -6,7 +6,7 @@
  * Status:	  Experimental.
  * Author:	  Dag Brattli <dagb@cs.uit.no>
  * Created at:	  Sun Aug  3 13:49:59 1997
- * Modified at:   Wed Jan  5 13:59:38 2000
+ * Modified at:   Fri Jan 28 20:22:38 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:	  serial.c by Linus Torvalds 
  * 
@@ -161,20 +161,19 @@
 	self->index = i;
 
 	/* Initialize IO */
-	self->io.iobase    = iobase;
+	self->io.sir_base  = iobase;
+        self->io.sir_ext   = IO_EXTENT;
         self->io.irq       = irq;
-        self->io.io_ext    = IO_EXTENT;
         self->io.fifo_size = 16;
 
 	/* Lock the port that we need */
-	ret = check_region(self->io.iobase, self->io.io_ext);
+	ret = check_region(self->io.sir_base, self->io.sir_ext);
 	if (ret < 0) { 
 		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-		      self->io.iobase);
-		/* irport_cleanup(self->self);  */
+			   self->io.sir_base);
 		return NULL;
 	}
-	request_region(self->io.iobase, self->io.io_ext, driver_name);
+	request_region(self->io.sir_base, self->io.sir_ext, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&self->qos);
@@ -218,7 +217,6 @@
 		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
 		return NULL;
 	}
-
 	self->netdev = dev;
 
 	/* May be overridden by piggyback drivers */
@@ -268,19 +266,19 @@
 
 	/* Release the IO-port that this driver is using */
 	IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
-		   self->io.iobase);
-	release_region(self->io.iobase, self->io.io_ext);
+		   self->io.sir_base);
+	release_region(self->io.sir_base, self->io.sir_ext);
 
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
 	
 	if (self->rx_buff.head)
 		kfree(self->rx_buff.head);
-
+	
 	/* Remove ourselves */
 	dev_self[self->index] = NULL;
 	kfree(self);
-
+	
 	return 0;
 }
 
@@ -289,7 +287,7 @@
 	unsigned long flags;
 	int iobase;
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	spin_lock_irqsave(&self->lock, flags);
 
@@ -310,7 +308,7 @@
 	unsigned long flags;
 	int iobase;
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	spin_lock_irqsave(&self->lock, flags);
 
@@ -355,7 +353,7 @@
 
 	ASSERT(self != NULL, return;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 	
 	/* Update accounting for new speed */
 	self->io.speed = speed;
@@ -431,7 +429,7 @@
 		break;
 	case IRDA_TASK_CHILD_INIT:
 		/* Go to default speed */
-		irport_change_speed(self, 9600);
+		self->change_speed(self->priv, 9600);
 
 		/* Change speed of dongle */
 		if (irda_task_execute(self->dongle,
@@ -454,7 +452,7 @@
 		break;
 	case IRDA_TASK_CHILD_DONE:
 		/* Finally we are ready to change the speed */
-		irport_change_speed(self, speed);
+		self->change_speed(self->priv, speed);
 		
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		break;
@@ -484,7 +482,7 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	/* Finished with frame?  */
 	if (self->tx_buff.len > 0)  {
@@ -598,7 +596,6 @@
 {
 	struct irport_cb *self;
 	unsigned long flags;
-	int actual = 0;
 	int iobase;
 	__u32 speed;
 
@@ -607,7 +604,7 @@
 	self = (struct irport_cb *) dev->priv;
 	ASSERT(self != NULL, return 0;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	/* Lock transmit buffer */
 	if (irda_lock((void *) &dev->tbusy) == FALSE) {
@@ -617,7 +614,7 @@
 
 		WARNING("%s: transmit timed out\n", dev->name);
 		irport_start(self);
-		irport_change_speed(self, self->io.speed );
+		self->change_speed(self->priv, self->io.speed);
 
 		dev->trans_start = jiffies;
 	}
@@ -635,8 +632,7 @@
 	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
 					   self->tx_buff.truesize);
 	
-	self->tx_buff.data += actual;
-	self->tx_buff.len  -= actual;
+	self->stats.tx_bytes += self->tx_buff.len;
 
 	/* Turn on transmit finished interrupt. Will fire immediately!  */
 	outb(UART_IER_THRI, iobase+UART_IER); 
@@ -661,7 +657,7 @@
 
 	ASSERT(self != NULL, return;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	/*  
 	 * Receive all characters in Rx FIFO, unwrap and unstuff them. 
@@ -702,15 +698,16 @@
 
 	dev->interrupt = 1;
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	iir = inb(iobase+UART_IIR) & UART_IIR_ID;
 	while (iir) {
 		/* Clear interrupt */
 		lsr = inb(iobase+UART_LSR);
 
-		IRDA_DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
-		      iir, lsr, iobase);
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+			   iir, lsr, iobase);
 
 		switch (iir) {
 		case UART_IIR_RLSI:
@@ -765,7 +762,7 @@
 	ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	if (request_irq(self->io.irq, self->interrupt, 0, dev->name, 
 			(void *) dev))
@@ -809,7 +806,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	/* Stop device */
 	dev->tbusy = 1;
@@ -840,7 +837,7 @@
 {
 	int iobase;
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	/* Wait until Tx FIFO is empty */
 	while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
@@ -875,7 +872,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	if (dtr)
 		dtr = UART_MCR_DTR;
@@ -895,7 +892,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.sir_base;
 
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- v2.3.41/linux/drivers/net/irda/irtty.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/irtty.c	Fri Jan 28 19:36:22 2000
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:18:38 1997
- * Modified at:   Wed Jan  5 14:00:13 2000
+ * Modified at:   Fri Jan 14 21:02:27 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -233,6 +233,8 @@
 		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
 		return -ENOMEM;
 	}
+	/* dev_alloc doesn't clear the struct */
+	memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
 
 	dev->priv = (void *) self;
 	self->netdev = dev;
@@ -654,6 +656,7 @@
 	self->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
 
 	dev->trans_start = jiffies;
+	self->stats.tx_bytes += self->tx_buff.len;
 
 	if (self->tty->driver.write)
 		actual = self->tty->driver.write(self->tty, 0, 
@@ -663,9 +666,6 @@
 	self->tx_buff.data += actual;
 	self->tx_buff.len -= actual;
 
-	self->stats.tx_packets++;
-	self->stats.tx_bytes += self->tx_buff.len;
-
 	dev_kfree_skb(skb);
 
 	return 0;
@@ -709,6 +709,8 @@
 
 		self->tx_buff.data += actual;
 		self->tx_buff.len  -= actual;
+
+		self->stats.tx_packets++;		      
 	} else {		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- v2.3.41/linux/drivers/net/irda/nsc-ircc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/nsc-ircc.c	Mon Jan 31 23:43:51 2000
@@ -0,0 +1,2073 @@
+/*********************************************************************
+ *                
+ * Filename:      nsc-ircc.c
+ * Version:       1.0
+ * Description:   Driver for the NSC PC'108 and PC'338 IrDA chipsets
+ * Status:        Stable.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sat Nov  7 21:43:15 1998
+ * Modified at:   Fri Jan 28 12:10:10 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
+ *     Copyright (c) 1998 Actisys Corp., www.actisys.com
+ *     All Rights Reserved
+ *      
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ *     Neither Dag Brattli nor University of Tromsř admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *
+ *     Notice that all functions that needs to access the chip in _any_
+ *     way, must save BSR register on entry, and restore it on exit. 
+ *     It is _very_ important to follow this policy!
+ *
+ *         __u8 bank;
+ *     
+ *         bank = inb(iobase+BSR);
+ *  
+ *         do_your_stuff_here();
+ *
+ *         outb(bank, iobase+BSR);
+ *
+ *    If you find bugs in this file, its very likely that the same bug
+ *    will also be in w83977af_ir.c since the implementations are quite
+ *    similar.
+ *     
+ ********************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irlap_frame.h>
+#include <net/irda/irda_device.h>
+
+#include <net/irda/nsc-ircc.h>
+
+#define CHIP_IO_EXTENT 8
+#define BROKEN_DONGLE_ID
+
+static char *driver_name = "nsc-ircc";
+
+/* Module parameters */
+static int qos_mtt_bits = 0x07;  /* 1 ms or more */
+static int dongle_id = 0;
+
+/* Use BIOS settions by default, but user may supply module parameters */
+static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = { 0, 0, 0, 0, 0 };
+static unsigned int dma[] = { 0, 0, 0, 0, 0 };
+
+static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
+static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
+
+/* These are the known NSC chips */
+static nsc_chip_t chips[] = {
+	{ "PC87108", { 0x150, 0x398, 0xea }, 0x05, 0x10, 0xf0, 
+	  nsc_ircc_probe_108, nsc_ircc_init_108 },
+	{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf0, 
+	  nsc_ircc_probe_338, nsc_ircc_init_338 },
+	{ NULL }
+};
+
+/* Max 4 instances for now */
+static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL };
+
+static char *dongle_types[] = {
+	"Differential serial interface",
+	"Differential serial interface",
+	"Reserved",
+	"Reserved",
+	"Sharp RY5HD01",
+	"Reserved",
+	"Single-ended serial interface",
+	"Consumer-IR only",
+	"HP HSDL-2300, HP HSDL-3600/HSDL-3610",
+	"IBM31T1100 or Temic TFDS6000/TFDS6500",
+	"Reserved",
+	"Reserved",
+	"HP HSDL-1100/HSDL-2100",
+	"HP HSDL-1100/HSDL-2100"
+	"Supports SIR Mode only",
+	"No dongle connected",
+};
+
+/* Some prototypes */
+static int  nsc_ircc_open(int i, chipio_t *info);
+#ifdef MODULE
+static int  nsc_ircc_close(struct nsc_ircc_cb *self);
+#endif /* MODULE */
+static int  nsc_ircc_setup(chipio_t *info);
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self);
+static int  nsc_ircc_dma_receive(struct nsc_ircc_cb *self); 
+static int  nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase);
+static int  nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
+static int  nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
+static int  nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase);
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 baud);
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int  nsc_ircc_is_receiving(struct nsc_ircc_cb *self);
+static int  nsc_ircc_read_dongle_id (int iobase);
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id);
+
+static int  nsc_ircc_net_init(struct net_device *dev);
+static int  nsc_ircc_net_open(struct net_device *dev);
+static int  nsc_ircc_net_close(struct net_device *dev);
+static int  nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
+#ifdef CONFIG_APM
+static int nsc_ircc_apmproc(apm_event_t event);
+#endif /* CONFIG_APM */
+
+/*
+ * Function nsc_ircc_init ()
+ *
+ *    Initialize chip. Just try to find out how many chips we are dealing with
+ *    and where they are
+ */
+int __init nsc_ircc_init(void)
+{
+	chipio_t info;
+	nsc_chip_t *chip;
+	int ret = -ENODEV;
+	int cfg_base;
+	int cfg, id;
+	int reg;
+	int i = 0;
+
+	/* Probe for all the NSC chipsets we know about */
+	for (chip=chips; chip->name ; chip++,i++) {
+		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", 
+			   chip->name);
+		
+		/* Try all config registers for this chip */
+		for (cfg=0; cfg<3; cfg++) {
+			cfg_base = chip->cfg[cfg];
+			if (!cfg_base)
+				continue;
+			
+			memset(&info, 0, sizeof(chipio_t));
+			info.cfg_base = cfg_base;
+			info.fir_base = io[i];
+			info.dma = dma[i];
+			info.irq = irq[i];
+
+			/* Read index register */
+			reg = inb(cfg_base);
+			if (reg == 0xff) {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "() no chip at 0x%03x\n", cfg_base);
+				continue;
+			}
+			
+			/* Read chip identification register */
+			outb(chip->cid_index, cfg_base);
+			id = inb(cfg_base+1);
+			if ((id & chip->cid_mask) == chip->cid_value) {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "() Found %s chip, revision=%d\n",
+					   chip->name, id & ~chip->cid_mask);
+				/* 
+				 * If the user supplies the base address, then
+				 * we init the chip, if not we probe the values
+				 * set by the BIOS
+				 */				
+				if (io[i] < 2000) {
+					chip->init(chip, &info);
+				} else
+					chip->probe(chip, &info);
+
+				if (nsc_ircc_open(i, &info) == 0)
+					ret = 0;
+				i++;
+			} else {
+				IRDA_DEBUG(2, __FUNCTION__ 
+					   "(), Wrong chip id=0x%02x\n", id);
+			}
+		} 
+		
+	}
+#ifdef CONFIG_APM
+	/* Make sure at least one chip was found before enabling APM */
+	if (ret == 0)
+		apm_register_callback(nsc_ircc_apmproc);
+#endif /* CONFIG_APM */
+
+	return ret;
+}
+
+/*
+ * Function nsc_ircc_cleanup ()
+ *
+ *    Close all configured chips
+ *
+ */
+#ifdef MODULE
+static void nsc_ircc_cleanup(void)
+{
+	int i;
+
+#ifdef CONFIG_APM
+	apm_unregister_callback(nsc_ircc_apmproc);
+#endif /* CONFIG_APM */
+
+	for (i=0; i < 4; i++) {
+		if (dev_self[i])
+			nsc_ircc_close(dev_self[i]);
+	}
+}
+#endif /* MODULE */
+
+/*
+ * Function nsc_ircc_open (iobase, irq)
+ *
+ *    Open driver instance
+ *
+ */
+static int nsc_ircc_open(int i, chipio_t *info)
+{
+	struct net_device *dev;
+	struct nsc_ircc_cb *self;
+	int ret;
+	int err;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	if ((nsc_ircc_setup(info)) == -1)
+		return -1;
+
+	/* Allocate new instance of the driver */
+	self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL);
+	if (self == NULL) {
+		ERROR(__FUNCTION__ "(), can't allocate memory for "
+		       "control block!\n");
+		return -ENOMEM;
+	}
+	memset(self, 0, sizeof(struct nsc_ircc_cb));
+	spin_lock_init(&self->lock);
+   
+	/* Need to store self somewhere */
+	dev_self[i] = self;
+	self->index = i;
+
+	/* Initialize IO */
+	self->io.cfg_base  = info->cfg_base;
+	self->io.fir_base  = info->fir_base;
+        self->io.irq       = info->irq;
+        self->io.fir_ext   = CHIP_IO_EXTENT;
+        self->io.dma       = info->dma;
+        self->io.fifo_size = 32;
+	
+	/* Reserve the ioports that we need */
+	ret = check_region(self->io.fir_base, self->io.fir_ext);
+	if (ret < 0) { 
+		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
+			self->io.fir_base);
+		dev_self[i] = NULL;
+		kfree(self);
+		return -ENODEV;
+	}
+	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&self->qos);
+	
+	/* The only value we must override it the baudrate */
+	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+		IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8);
+	
+	self->qos.min_turn_time.bits = qos_mtt_bits;
+	irda_qos_bits_to_value(&self->qos);
+	
+	self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
+
+	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+	self->rx_buff.truesize = 14384; 
+	self->tx_buff.truesize = 14384;
+
+	/* Allocate memory if needed */
+	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
+					      GFP_KERNEL|GFP_DMA);
+	if (self->rx_buff.head == NULL) {
+		kfree(self);
+		return -ENOMEM;
+	}
+	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
+	
+	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
+					      GFP_KERNEL|GFP_DMA);
+	if (self->tx_buff.head == NULL) {
+		kfree(self);
+		kfree(self->rx_buff.head);
+		return -ENOMEM;
+	}
+	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
+
+	self->rx_buff.in_frame = FALSE;
+	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Reset Tx queue info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+
+	if (!(dev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -ENOMEM;
+	}
+
+	dev->priv = (void *) self;
+	self->netdev = dev;
+
+	/* Override the network functions we need to use */
+	dev->init            = nsc_ircc_net_init;
+	dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+	dev->open            = nsc_ircc_net_open;
+	dev->stop            = nsc_ircc_net_close;
+	dev->do_ioctl        = nsc_ircc_net_ioctl;
+	dev->get_stats	     = nsc_ircc_net_get_stats;
+
+	rtnl_lock();
+	err = register_netdevice(dev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
+	MESSAGE("IrDA: Registered device %s\n", dev->name);
+
+	/* Check if user has supplied the dongle id or not */
+	if (!dongle_id) {
+		dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base);
+		
+		MESSAGE("%s, Found dongle: %s\n", driver_name,
+			dongle_types[dongle_id]);
+	} else {
+		MESSAGE("%s, Using dongle: %s\n", driver_name,
+			dongle_types[dongle_id]);
+	}
+	
+	self->io.dongle_id = dongle_id;
+	nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id);
+
+	return 0;
+}
+
+#ifdef MODULE
+/*
+ * Function nsc_ircc_close (self)
+ *
+ *    Close driver instance
+ *
+ */
+static int nsc_ircc_close(struct nsc_ircc_cb *self)
+{
+	int iobase;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+
+        iobase = self->io.fir_base;
+
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		rtnl_unlock();
+	}
+
+	/* Release the PORT that this driver is using */
+	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", 
+		   self->io.fir_base);
+	release_region(self->io.fir_base, self->io.fir_ext);
+
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
+	
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
+
+	dev_self[self->index] = NULL;
+	kfree(self);
+	
+	return 0;
+}
+#endif /* MODULE */
+
+/*
+ * Function nsc_ircc_init_108 (iobase, cfg_base, irq, dma)
+ *
+ *    Initialize the NSC '108 chip
+ *
+ */
+static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info)
+{
+	int cfg_base = info->cfg_base;
+	__u8 temp=0;
+
+	outb(2, cfg_base);      /* Mode Control Register (MCTL) */
+	outb(0x00, cfg_base+1); /* Disable device */
+	
+	/* Base Address and Interrupt Control Register (BAIC) */
+	outb(0, cfg_base);
+	switch (info->fir_base) {
+	case 0x3e8: outb(0x14, cfg_base+1); break;
+	case 0x2e8: outb(0x15, cfg_base+1); break;
+	case 0x3f8: outb(0x16, cfg_base+1); break;
+	case 0x2f8: outb(0x17, cfg_base+1); break;
+	default: ERROR(__FUNCTION__ "(), invalid base_address");
+	}
+	
+	/* Control Signal Routing Register (CSRT) */
+	switch (info->irq) {
+	case 3:  temp = 0x01; break;
+	case 4:  temp = 0x02; break;
+	case 5:  temp = 0x03; break;
+	case 7:  temp = 0x04; break;
+	case 9:  temp = 0x05; break;
+	case 11: temp = 0x06; break;
+	case 15: temp = 0x07; break;
+	default: ERROR(__FUNCTION__ "(), invalid irq");
+	}
+	outb(1, cfg_base);
+	
+	switch (info->dma) {	
+	case 0: outb(0x08+temp, cfg_base+1); break;
+	case 1: outb(0x10+temp, cfg_base+1); break;
+	case 3: outb(0x18+temp, cfg_base+1); break;
+	default: ERROR(__FUNCTION__ "(), invalid dma");
+	}
+	
+	outb(2, cfg_base);      /* Mode Control Register (MCTL) */
+	outb(0x03, cfg_base+1); /* Enable device */
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_probe_108 (chip, info)
+ *
+ *    
+ *
+ */
+static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info) 
+{
+	int cfg_base = info->cfg_base;
+	int reg;
+
+	/* Read address and interrupt control register (BAIC) */
+	outb(CFG_BAIC, cfg_base);
+	reg = inb(cfg_base+1);
+	
+	switch (reg & 0x03) {
+	case 0:
+		info->fir_base = 0x3e8;
+		break;
+	case 1:
+		info->fir_base = 0x2e8;
+		break;
+	case 2:
+		info->fir_base = 0x3f8;
+		break;
+	case 3:
+		info->fir_base = 0x2f8;
+		break;
+	}
+	info->sir_base = info->fir_base;
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", 
+		   info->fir_base);
+
+	/* Read control signals routing register (CSRT) */
+	outb(CFG_CSRT, cfg_base);
+	reg = inb(cfg_base+1);
+
+	switch (reg & 0x07) {
+	case 0:
+		info->irq = -1;
+		break;
+	case 1:
+		info->irq = 3;
+		break;
+	case 2:
+		info->irq = 4;
+		break;
+	case 3:
+		info->irq = 5;
+		break;
+	case 4:
+		info->irq = 7;
+		break;
+	case 5:
+		info->irq = 9;
+		break;
+	case 6:
+		info->irq = 11;
+		break;
+	case 7:
+		info->irq = 15;
+		break;
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+
+	/* Currently we only read Rx DMA but it will also be used for Tx */
+	switch ((reg >> 3) & 0x03) {
+	case 0:
+		info->dma = -1;
+		break;
+	case 1:
+		info->dma = 0;
+		break;
+	case 2:
+		info->dma = 1;
+		break;
+	case 3:
+		info->dma = 3;
+		break;
+	}
+	IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+
+	/* Read mode control register (MCTL) */
+	outb(CFG_MCTL, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->enabled = reg & 0x01;
+	info->suspended = !((reg >> 1) & 0x01);
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_init_338 (chip, info)
+ *
+ *    Initialize the NSC '338 chip. Remember that the 87338 needs two 
+ *    consecutive writes to the data registers while CPU interrupts are
+ *    disabled. The 97338 does not require this, but shouldn't be any
+ *    harm if we do it anyway.
+ */
+static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info) 
+{
+	/* No init yet */
+	
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_probe_338 (chip, info)
+ *
+ *    
+ *
+ */
+static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) 
+{
+	int cfg_base = info->cfg_base;
+	int reg, com = 0;
+	int pnp;
+
+	/* Read funtion enable register (FER) */
+	outb(CFG_FER, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->enabled = (reg >> 2) & 0x01;
+
+	/* Check if we are in Legacy or PnP mode */
+	outb(CFG_PNP0, cfg_base);
+	reg = inb(cfg_base+1);
+	
+	pnp = (reg >> 4) & 0x01;
+	if (pnp) {
+		IRDA_DEBUG(2, "(), Chip is in PnP mode\n");
+		outb(0x46, cfg_base);
+		reg = (inb(cfg_base+1) & 0xfe) << 2;
+
+		outb(0x47, cfg_base);
+		reg |= ((inb(cfg_base+1) & 0xfc) << 8);
+
+		info->fir_base = reg;
+	} else {
+		/* Read function address register (FAR) */
+		outb(CFG_FAR, cfg_base);
+		reg = inb(cfg_base+1);
+		
+		switch ((reg >> 4) & 0x03) {
+		case 0:
+			info->fir_base = 0x3f8;
+			break;
+		case 1:
+			info->fir_base = 0x2f8;
+			break;
+		case 2:
+			com = 3;
+			break;
+		case 3:
+			com = 4;
+			break;
+		}
+		
+		if (com) {
+			switch ((reg >> 6) & 0x03) {
+			case 0:
+				if (com == 3)
+					info->fir_base = 0x3e8;
+				else
+					info->fir_base = 0x2e8;
+				break;
+			case 1:
+				if (com == 3)
+					info->fir_base = 0x338;
+				else
+					info->fir_base = 0x238;
+				break;
+			case 2:
+				if (com == 3)
+					info->fir_base = 0x2e8;
+				else
+					info->fir_base = 0x2e0;
+				break;
+			case 3:
+				if (com == 3)
+					info->fir_base = 0x220;
+				else
+					info->fir_base = 0x228;
+				break;
+			}
+		}
+	}
+	info->sir_base = info->fir_base;
+
+	/* Read PnP register 1 (PNP1) */
+	outb(CFG_PNP1, cfg_base);
+	reg = inb(cfg_base+1);
+	
+	info->irq = reg >> 4;
+	
+	/* Read PnP register 3 (PNP3) */
+	outb(CFG_PNP3, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->dma = (reg & 0x07) - 1;
+
+	/* Read power and test register (PTR) */
+	outb(CFG_PTR, cfg_base);
+	reg = inb(cfg_base+1);
+
+	info->suspended = reg & 0x01;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_setup (info)
+ *
+ *    Returns non-negative on success.
+ *
+ */
+static int nsc_ircc_setup(chipio_t *info)
+{
+	int version;
+	int iobase = info->fir_base;
+
+	/* Read the Module ID */
+	switch_bank(iobase, BANK3);
+	version = inb(iobase+MID);
+
+	/* Should be 0x2? */
+	if (0x20 != (version & 0xf0)) {
+		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
+		return -1;
+	}
+	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, 
+		info->cfg_base);
+
+	/* Switch to advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_EXT_SL, iobase+ECR1);
+	switch_bank(iobase, BANK0);
+	
+	/* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
+	switch_bank(iobase, BANK0);	
+	outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
+	
+	/* Set FIFO size to 32 */
+	switch_bank(iobase, BANK2);
+	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
+
+	/* IRCR2: FEND_MD is set */
+	switch_bank(iobase, BANK5);
+ 	outb(0x2a, iobase+4);
+
+	/* Make sure that some defaults are OK */
+	switch_bank(iobase, BANK6);
+	outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
+	outb(0x0a, iobase+1); /* Set MIR pulse width */
+	outb(0x0d, iobase+2); /* Set SIR pulse width */
+	outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
+
+	MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
+
+	/* Enable receive interrupts */
+	switch_bank(iobase, BANK0);
+	outb(IER_RXHDL_IE, iobase+IER);
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_read_dongle_id (void)
+ *
+ * Try to read dongle indentification. This procedure needs to be executed
+ * once after power-on/reset. It also needs to be used whenever you suspect
+ * that the user may have plugged/unplugged the IrDA Dongle.
+ */
+static int nsc_ircc_read_dongle_id (int iobase)
+{
+	int dongle_id;
+	__u8 bank;
+
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
+	outb(0x00, iobase+7);
+	
+	/* ID0, 1, and 2 are pulled up/down very slowly */
+	udelay(50);
+	
+	/* IRCFG1: read the ID bits */
+	dongle_id = inb(iobase+4) & 0x0f;
+
+#ifdef BROKEN_DONGLE_ID
+	if (dongle_id == 0x0a)
+		dongle_id = 0x09;
+#endif	
+	/* Go back to  bank 0 before returning */
+	switch_bank(iobase, BANK0);
+
+	outb(bank, iobase+BSR);
+
+	return dongle_id;
+}
+
+/*
+ * Function nsc_ircc_init_dongle_interface (iobase, dongle_id)
+ *
+ *     This function initializes the dongle for the transceiver that is
+ *     used. This procedure needs to be executed once after
+ *     power-on/reset. It also needs to be used whenever you suspect that
+ *     the dongle is changed. 
+ */
+static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id)
+{
+	int bank;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG4: set according to dongle_id */
+	switch (dongle_id) {
+	case 0x00: /* same as */
+	case 0x01: /* Differential serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x02: /* same as */
+	case 0x03: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x04: /* Sharp RY5HD01 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x05: /* Reserved, but this is what the Thinkpad reports */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x06: /* Single-ended serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x07: /* Consumer-IR only */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
+			   dongle_types[dongle_id]);
+		break;
+	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
+		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
+		break;
+	case 0x0A: /* same as */
+	case 0x0B: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x0C: /* same as */
+	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
+		/* 
+		 * Set irsl0 as input, irsl[1-2] as output, and separate 
+		 * inputs are used for SIR and MIR/FIR 
+		 */
+		outb(0x48, iobase+7); 
+		break;
+	case 0x0E: /* Supports SIR Mode only */
+		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
+		break;
+	case 0x0F: /* No dongle connected */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
+			   dongle_types[dongle_id]); 
+
+		switch_bank(iobase, BANK0);
+		outb(0x62, iobase+MCR);
+		break;
+	default: 
+		IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", 
+			   dongle_id);
+	}
+	
+	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
+	outb(0x00, iobase+4);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+	
+} /* set_up_dongle_interface */
+
+/*
+ * Function nsc_ircc_change_dongle_speed (iobase, speed, dongle_id)
+ *
+ *    Change speed of the attach dongle
+ *
+ */
+static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
+{
+	unsigned long flags;
+	__u8 bank;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Select Bank 7 */
+	switch_bank(iobase, BANK7);
+	
+	/* IRCFG1: set according to dongle_id */
+	switch (dongle_id) {
+	case 0x00: /* same as */
+	case 0x01: /* Differential serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x02: /* same as */
+	case 0x03: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x04: /* Sharp RY5HD01 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
+			   dongle_types[dongle_id]); 
+	case 0x05: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x06: /* Single-ended serial interface */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x07: /* Consumer-IR only */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", 
+			   dongle_types[dongle_id]); 
+		outb(0x00, iobase+4);
+		if (speed > 115200)
+			outb(0x01, iobase+4);
+		break;
+	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
+		outb(0x01, iobase+4);
+
+		if (speed == 4000000) {
+			save_flags(flags);
+			cli();
+			outb(0x81, iobase+4);
+			outb(0x80, iobase+4);
+			restore_flags(flags);
+		} else
+			outb(0x00, iobase+4);
+		break;
+	case 0x0A: /* same as */
+	case 0x0B: /* Reserved */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
+			   dongle_types[dongle_id]); 
+		break;
+	case 0x0C: /* same as */
+	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
+		break;
+	case 0x0E: /* Supports SIR Mode only */
+		break;
+	case 0x0F: /* No dongle connected */
+		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
+			   dongle_types[dongle_id]);
+
+		switch_bank(iobase, BANK0); 
+		outb(0x62, iobase+MCR);
+		break;
+	default: 
+		IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n");
+	}
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_change_speed (self, baud)
+ *
+ *    Change the speed of the device
+ *
+ */
+static void nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
+{
+	struct net_device *dev = self->netdev;
+	__u8 mcr = MCR_SIR;
+	int iobase; 
+	__u8 bank;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed);
+
+	ASSERT(self != NULL, return;);
+
+	iobase = self->io.fir_base;
+
+	/* Update accounting for new speed */
+	self->io.speed = speed;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable interrupts */
+	switch_bank(iobase, BANK0);
+	outb(0, iobase+IER);
+
+	/* Select Bank 2 */
+	switch_bank(iobase, BANK2);
+
+	outb(0x00, iobase+BGDH);
+	switch (speed) {
+	case 9600:   outb(0x0c, iobase+BGDL); break;
+	case 19200:  outb(0x06, iobase+BGDL); break;
+	case 38400:  outb(0x03, iobase+BGDL); break;
+	case 57600:  outb(0x02, iobase+BGDL); break;
+	case 115200: outb(0x01, iobase+BGDL); break;
+	case 576000:
+		switch_bank(iobase, BANK5);
+		
+		/* IRCR2: MDRS is set */
+		outb(inb(iobase+4) | 0x04, iobase+4);
+	       
+		mcr = MCR_MIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
+		break;
+	case 1152000:
+		mcr = MCR_MIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
+		break;
+	case 4000000:
+		mcr = MCR_FIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
+		break;
+	default:
+		mcr = MCR_FIR;
+		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
+			   speed);
+		break;
+	}
+
+	/* Set appropriate speed mode */
+	switch_bank(iobase, BANK0);
+	outb(mcr | MCR_TX_DFR, iobase+MCR);
+
+	/* Give some hits to the transceiver */
+	nsc_ircc_change_dongle_speed(iobase, speed, self->io.dongle_id);
+
+	/* Set FIFO threshold to TX17, RX16 */
+	switch_bank(iobase, BANK0);
+	outb(0x00, iobase+FCR);
+	outb(FCR_FIFO_EN, iobase+FCR);
+	outb(FCR_RXTH|     /* Set Rx FIFO threshold */
+	     FCR_TXTH|     /* Set Tx FIFO threshold */
+	     FCR_TXSR|     /* Reset Tx FIFO */
+	     FCR_RXSR|     /* Reset Rx FIFO */
+	     FCR_FIFO_EN,  /* Enable FIFOs */
+	     iobase+FCR);
+	
+	/* Set FIFO size to 32 */
+	switch_bank(iobase, BANK2);
+	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
+	
+	self->netdev->tbusy = 0;
+	
+	/* Enable some interrupts so we can receive frames */
+	switch_bank(iobase, BANK0); 
+	if (speed > 115200) {
+		/* Install FIR xmit handler */
+		dev->hard_start_xmit = nsc_ircc_hard_xmit_fir;
+		outb(IER_SFIF_IE, iobase+IER);
+		nsc_ircc_dma_receive(self);
+	} else {
+		/* Install SIR xmit handler */
+		dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+		outb(IER_RXHDL_IE, iobase+IER);
+	}
+    	
+	/* Restore BSR */
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_hard_xmit (skb, dev)
+ *
+ *    Transmit the frame!
+ *
+ */
+static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
+{
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	__u8 bank;
+	
+	self = (struct nsc_ircc_cb *) dev->priv;
+
+	ASSERT(self != NULL, return 0;);
+
+	iobase = self->io.fir_base;
+
+	/* Lock transmit buffer */
+	if (irda_lock((void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+	
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+	
+	spin_lock_irqsave(&self->lock, flags);
+	
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	self->tx_buff.data = self->tx_buff.head;
+	
+	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
+					   self->tx_buff.truesize);
+
+	self->stats.tx_bytes += self->tx_buff.len;
+	
+	/* Add interrupt on tx low level (will fire immediately) */
+	switch_bank(iobase, BANK0);
+	outb(IER_TXLDL_IE, iobase+IER);
+	
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
+{
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int iobase;
+	__u32 speed;
+	__u8 bank;
+	int mtt, diff;
+	
+	self = (struct nsc_ircc_cb *) dev->priv;
+	iobase = self->io.fir_base;
+
+	/* Lock transmit buffer */
+	if (irda_lock((void *) &dev->tbusy) == FALSE)
+		return -EBUSY;
+
+	/* Check if we need to change the speed */
+	if ((speed = irda_get_speed(skb)) != self->io.speed)
+		self->new_speed = speed;
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Register and copy this frame to DMA memory */
+	self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
+	self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
+	self->tx_fifo.tail += skb->len;
+
+	self->stats.tx_bytes += skb->len;
+
+	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, 
+	       skb->len);
+	
+	self->tx_fifo.len++;
+	self->tx_fifo.free++;
+
+	/* Start transmit only if there is currently no transmit going on */
+	if (self->tx_fifo.len == 1) {
+		/* Check if we must wait the min turn time or not */
+		mtt = irda_get_mtt(skb);
+		if (mtt) {
+			/* Check how much time we have used already */
+			get_fast_time(&self->now);
+			diff = self->now.tv_usec - self->stamp.tv_usec;
+			if (diff < 0) 
+				diff += 1000000;
+			
+			/* Check if the mtt is larger than the time we have
+			 * already used by all the protocol processing
+			 */
+			if (mtt > diff) {
+				mtt -= diff;
+
+				/* 
+				 * Use timer if delay larger than 125 us, and
+				 * use udelay for smaller values which should
+				 * be acceptable
+				 */
+				if (mtt > 125) {
+					/* Adjust for timer resolution */
+					mtt = mtt / 125;
+					
+					/* Setup timer */
+					switch_bank(iobase, BANK4);
+					outb(mtt & 0xff, iobase+TMRL);
+					outb((mtt >> 8) & 0x0f, iobase+TMRH);
+					
+					/* Start timer */
+					outb(IRCR1_TMR_EN, iobase+IRCR1);
+					self->io.direction = IO_XMIT;
+					
+					/* Enable timer interrupt */
+					switch_bank(iobase, BANK0);
+					outb(IER_TMR_IE, iobase+IER);
+					
+					/* Timer will take care of the rest */
+					goto out; 
+				} else
+					udelay(mtt);
+			}
+		}		
+		/* Enable DMA interrupt */
+		switch_bank(iobase, BANK0);
+		outb(IER_DMA_IE, iobase+IER);
+
+		/* Transmit frame */
+		nsc_ircc_dma_xmit(self, iobase);
+	}
+ out:
+	/* Not busy transmitting anymore if window is not full */
+	if (self->tx_fifo.free < MAX_TX_WINDOW)
+		dev->tbusy = 0;
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	spin_unlock_irqrestore(&self->lock, flags);
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_dma_xmit (self, iobase)
+ *
+ *    Transmit data using DMA
+ *
+ */
+static void nsc_ircc_dma_xmit(struct nsc_ircc_cb *self, int iobase)
+{
+	int bsr;
+
+	/* Save current bank */
+	bsr = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+	
+	self->io.direction = IO_XMIT;
+	
+	/* Choose transmit DMA channel  */ 
+	switch_bank(iobase, BANK2);
+	outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
+	
+	setup_dma(self->io.dma, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].start, 
+		  self->tx_fifo.queue[self->tx_fifo.ptr].len, 
+		  DMA_TX_MODE);
+
+	/* Enable DMA and SIR interaction pulse */
+ 	switch_bank(iobase, BANK0);	
+	outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR);
+
+	/* Restore bank register */
+	outb(bsr, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_pio_xmit (self, iobase)
+ *
+ *    Transmit data using PIO. Returns the number of bytes that actually
+ *    got transfered
+ *
+ */
+static int nsc_ircc_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
+{
+	int actual = 0;
+	__u8 bank;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	switch_bank(iobase, BANK0);
+	if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
+		IRDA_DEBUG(4, __FUNCTION__ 
+			   "(), warning, FIFO not empty yet!\n");
+
+		/* FIFO may still be filled to the Tx interrupt threshold */
+		fifo_size -= 17;
+	}
+
+	/* Fill FIFO with current frame */
+	while ((fifo_size-- > 0) && (actual < len)) {
+		/* Transmit next byte */
+		outb(buf[actual++], iobase+TXD);
+	}
+        
+	IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
+		   fifo_size, actual, len);
+	
+	/* Restore bank */
+	outb(bank, iobase+BSR);
+
+	return actual;
+}
+
+/*
+ * Function nsc_ircc_dma_xmit_complete (self)
+ *
+ *    The transfer of a frame in finished. This function will only be called 
+ *    by the interrupt handler
+ *
+ */
+static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
+{
+	int iobase;
+	__u8 bank;
+	int ret = TRUE;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	iobase = self->io.fir_base;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+        outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+	
+	/* Check for underrrun! */
+	if (inb(iobase+ASCR) & ASCR_TXUR) {
+		self->stats.tx_errors++;
+		self->stats.tx_fifo_errors++;
+		
+		/* Clear bit, by writing 1 into it */
+		outb(ASCR_TXUR, iobase+ASCR);
+	} else {
+		self->stats.tx_packets++;
+	}
+
+	/* Check if we need to change the speed */
+	if (self->new_speed) {
+		nsc_ircc_change_speed(self, self->new_speed);
+		self->new_speed = 0;
+	}
+
+	/* Finished with this frame, so prepare for next */
+	self->tx_fifo.ptr++;
+	self->tx_fifo.len--;
+
+	/* Any frames to be sent back-to-back? */
+	if (self->tx_fifo.len) {
+		nsc_ircc_dma_xmit(self, iobase);
+		
+		/* Not finished yet! */
+		ret = FALSE;
+	} else {
+		/* Reset Tx FIFO info */
+		self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+		self->tx_fifo.tail = self->tx_buff.head;
+	}
+
+	/* Make sure we have room for more frames */
+	if (self->tx_fifo.free < MAX_TX_WINDOW) {
+		/* Not busy transmitting anymore */
+		self->netdev->tbusy = 0;
+
+		/* Tell the network layer, that we can accept more frames */
+		mark_bh(NET_BH);
+	}
+
+	/* Restore bank */
+	outb(bank, iobase+BSR);
+	
+	return ret;
+}
+
+/*
+ * Function nsc_ircc_dma_receive (self)
+ *
+ *    Get ready for receiving a frame. The device will initiate a DMA
+ *    if it starts to receive a frame.
+ *
+ */
+static int nsc_ircc_dma_receive(struct nsc_ircc_cb *self) 
+{
+	int iobase;
+	__u8 bsr;
+
+	iobase = self->io.fir_base;
+
+	/* Reset Tx FIFO info */
+	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
+	self->tx_fifo.tail = self->tx_buff.head;
+
+	/* Save current bank */
+	bsr = inb(iobase+BSR);
+
+	/* Disable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
+
+	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
+
+	self->io.direction = IO_RECV;
+	self->rx_buff.data = self->rx_buff.head;
+	
+	/* Reset Rx FIFO. This will also flush the ST_FIFO */
+	switch_bank(iobase, BANK0);
+	outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
+
+	self->st_fifo.len = self->st_fifo.pending_bytes = 0;
+	self->st_fifo.tail = self->st_fifo.head = 0;
+	
+	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
+		  DMA_RX_MODE);
+
+	/* Enable DMA */
+	switch_bank(iobase, BANK0);
+	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
+
+	/* Restore bank register */
+	outb(bsr, iobase+BSR);
+	
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_dma_receive_complete (self)
+ *
+ *    Finished with receiving frames
+ *
+ *    
+ */
+static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
+{
+	struct st_fifo *st_fifo;
+	struct sk_buff *skb;
+	__u8 status;
+	__u8 bank;
+	int len;
+
+	st_fifo = &self->st_fifo;
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	/* Read all entries in status FIFO */
+	switch_bank(iobase, BANK5);
+	while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) {
+		/* We must empty the status FIFO no matter what */
+		len = inb(iobase+RFLFL) | ((inb(iobase+RFLFH) & 0x1f) << 8);
+
+		if (st_fifo->tail >= MAX_RX_WINDOW)
+			continue;
+			
+		st_fifo->entries[st_fifo->tail].status = status;
+		st_fifo->entries[st_fifo->tail].len = len;
+		st_fifo->pending_bytes += len;
+		st_fifo->tail++;
+		st_fifo->len++;
+	}
+	/* Try to process all entries in status FIFO */
+	while (st_fifo->len > 0) {
+		/* Get first entry */
+		status = st_fifo->entries[st_fifo->head].status;
+		len    = st_fifo->entries[st_fifo->head].len;
+		st_fifo->pending_bytes -= len;
+		st_fifo->head++;
+		st_fifo->len--;
+
+		/* Check for errors */
+		if (status & FRM_ST_ERR_MSK) {
+			if (status & FRM_ST_LOST_FR) {
+				/* Add number of lost frames to stats */
+				self->stats.rx_errors += len;	
+			} else {
+				/* Skip frame */
+				self->stats.rx_errors++;
+				
+				self->rx_buff.data += len;
+			
+				if (status & FRM_ST_MAX_LEN)
+					self->stats.rx_length_errors++;
+				
+				if (status & FRM_ST_PHY_ERR) 
+					self->stats.rx_frame_errors++;
+				
+				if (status & FRM_ST_BAD_CRC) 
+					self->stats.rx_crc_errors++;
+			}
+			/* The errors below can be reported in both cases */
+			if (status & FRM_ST_OVR1)
+				self->stats.rx_fifo_errors++;		       
+			
+			if (status & FRM_ST_OVR2)
+				self->stats.rx_fifo_errors++;
+		} else {
+			/*  
+			 * First we must make sure that the frame we
+			 * want to deliver is all in main memory. If we
+			 * cannot tell, then we check if the Rx FIFO is
+			 * empty. If not then we will have to take a nap
+			 * and try again later.  
+			 */
+			if (st_fifo->pending_bytes < self->io.fifo_size) {
+				switch_bank(iobase, BANK0);
+				if (inb(iobase+LSR) & LSR_RXDA) {
+					/* Put this entry back in fifo */
+					st_fifo->head--;
+					st_fifo->len++;
+					st_fifo->pending_bytes += len;
+					st_fifo->entries[st_fifo->head].status = status;
+					st_fifo->entries[st_fifo->head].len = len;
+				
+					/* Restore bank register */
+					outb(bank, iobase+BSR);
+					
+					return FALSE; /* I'll be back! */
+				}
+			}
+
+			/* 
+			 * Remember the time we received this frame, so we can
+			 * reduce the min turn time a bit since we will know
+			 * how much time we have used for protocol processing
+			 */
+			get_fast_time(&self->stamp);
+
+			skb = dev_alloc_skb(len+1);
+			if (skb == NULL)  {
+				WARNING(__FUNCTION__ "(), memory squeeze, "
+					"dropping frame.\n");
+				self->stats.rx_dropped++;
+
+				/* Restore bank register */
+				outb(bank, iobase+BSR);
+
+				return FALSE;
+			}
+			
+			/* Make sure IP header gets aligned */
+			skb_reserve(skb, 1); 
+
+			/* Copy frame without CRC */
+			if (self->io.speed < 4000000) {
+				skb_put(skb, len-2);
+				memcpy(skb->data, self->rx_buff.data, len-2);
+			} else {
+				skb_put(skb, len-4);
+				memcpy(skb->data, self->rx_buff.data, len-4);
+			}
+
+			/* Move to next frame */
+			self->rx_buff.data += len;
+			self->stats.rx_bytes += len;
+			self->stats.rx_packets++;
+
+			skb->dev = self->netdev;
+			skb->mac.raw  = skb->data;
+			skb->protocol = htons(ETH_P_IRDA);
+			netif_rx(skb);
+		}
+	}
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	return TRUE;
+}
+
+/*
+ * Function nsc_ircc_pio_receive (self)
+ *
+ *    Receive all data in receiver FIFO
+ *
+ */
+static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) 
+{
+	__u8 byte;
+	int iobase;
+
+	iobase = self->io.fir_base;
+	
+	/*  Receive all characters in Rx FIFO */
+	do {
+		byte = inb(iobase+RXD);
+		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
+				  byte);
+	} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */	
+}
+
+/*
+ * Function nsc_ircc_sir_interrupt (self, eir)
+ *
+ *    Handle SIR interrupt
+ *
+ */
+static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
+{
+	int actual;
+
+	/* Check if transmit FIFO is low on data */
+	if (eir & EIR_TXLDL_EV) {
+		/* Write data left in transmit buffer */
+		actual = nsc_ircc_pio_write(self->io.fir_base, 
+					   self->tx_buff.data, 
+					   self->tx_buff.len, 
+					   self->io.fifo_size);
+		self->tx_buff.data += actual;
+		self->tx_buff.len  -= actual;
+		
+		self->io.direction = IO_XMIT;
+
+		/* Check if finished */
+		if (self->tx_buff.len > 0)
+			self->ier = IER_TXLDL_IE;
+		else { 
+			self->netdev->tbusy = 0; /* Unlock */
+			self->stats.tx_packets++;
+			
+		        mark_bh(NET_BH);	
+
+			self->ier = IER_TXEMP_IE;
+		}
+			
+	}
+	/* Check if transmission has completed */
+	if (eir & EIR_TXEMP_EV) {
+		/* Check if we need to change the speed? */
+		if (self->new_speed) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n");
+			nsc_ircc_change_speed(self, self->new_speed);
+			self->new_speed = 0;
+
+			/* Check if we are going to FIR */
+			if (self->io.speed > 115200) {
+				/* Should wait for status FIFO interrupt */
+				self->ier = IER_SFIF_IE;
+
+				/* No need to do anymore SIR stuff */
+				return;
+			}
+		}
+		/* Turn around and get ready to receive some data */
+		self->io.direction = IO_RECV;
+		self->ier = IER_RXHDL_IE;
+	}
+
+	/* Rx FIFO threshold or timeout */
+	if (eir & EIR_RXHDL_EV) {
+		nsc_ircc_pio_receive(self);
+
+		/* Keep receiving */
+		self->ier = IER_RXHDL_IE;
+	}
+}
+
+/*
+ * Function nsc_ircc_fir_interrupt (self, eir)
+ *
+ *    Handle MIR/FIR interrupt
+ *
+ */
+static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase, 
+				   int eir)
+{
+	__u8 bank;
+
+	bank = inb(iobase+BSR);
+	
+	/* Status FIFO event*/
+	if (eir & EIR_SFIF_EV) {
+		if (nsc_ircc_dma_receive_complete(self, iobase)) {
+			/* Wait for next status FIFO interrupt */
+			self->ier = IER_SFIF_IE;
+		} else {
+			/* 
+			 * DMA not finished yet, so try again later, set 
+			 * timer value, resolution 125 us 
+			 */
+			switch_bank(iobase, BANK4);
+			outb(0x02, iobase+TMRL); /* 2 * 125 us */
+			outb(0x00, iobase+TMRH);
+
+			/* Start timer */
+			outb(IRCR1_TMR_EN, iobase+IRCR1);
+			self->ier = IER_TMR_IE | IER_SFIF_IE;
+		}
+	} else if (eir & EIR_TMR_EV) { /* Timer finished */
+		/* Disable timer */
+		switch_bank(iobase, BANK4);
+		outb(0, iobase+IRCR1);
+
+		/* Clear timer event */
+		switch_bank(iobase, BANK0);
+		outb(ASCR_CTE, iobase+ASCR);
+
+		/* Check if this is a Tx timer interrupt */
+		if (self->io.direction == IO_XMIT) {
+			nsc_ircc_dma_xmit(self, iobase);
+
+			/*  Interrupt on DMA */
+			self->ier = IER_DMA_IE;
+		} else {
+			/* Check if DMA has now finished */
+			nsc_ircc_dma_receive_complete(self, iobase);
+
+			self->ier = IER_SFIF_IE;
+		}
+	} else if (eir & EIR_DMA_EV) { 
+		/* Finished with all transmissions? */
+		if (nsc_ircc_dma_xmit_complete(self)) {		
+			/* Check if there are more frames to be transmitted */
+			if (irda_device_txqueue_empty(self->netdev)) {
+				/* Prepare for receive */
+				nsc_ircc_dma_receive(self);
+			
+				self->ier = IER_SFIF_IE;
+			}
+		} else {
+			/*  Not finished yet, so interrupt on DMA again */
+			self->ier = IER_DMA_IE;
+		}
+	}
+	outb(bank, iobase+BSR);
+}
+
+/*
+ * Function nsc_ircc_interrupt (irq, dev_id, regs)
+ *
+ *    An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static void nsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct nsc_ircc_cb *self;
+	__u8 bsr, eir;
+	int iobase;
+
+	if (!dev) {
+		WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
+		return;
+	}
+	self = (struct nsc_ircc_cb *) dev->priv;
+
+	spin_lock(&self->lock);	
+	dev->interrupt = 1;
+
+	iobase = self->io.fir_base;
+
+	bsr = inb(iobase+BSR); 	/* Save current bank */
+
+	switch_bank(iobase, BANK0);	
+	self->ier = inb(iobase+IER); 
+	eir = inb(iobase+EIR) & self->ier; /* Mask out the interesting ones */ 
+
+	outb(0, iobase+IER); /* Disable interrupts */
+	
+	if (eir) {
+		/* Dispatch interrupt handler for the current speed */
+		if (self->io.speed > 115200)
+			nsc_ircc_fir_interrupt(self, iobase, eir);
+		else
+			nsc_ircc_sir_interrupt(self, eir);
+	}
+	
+	outb(self->ier, iobase+IER); /* Restore interrupts */
+	outb(bsr, iobase+BSR);       /* Restore bank register */
+
+	dev->interrupt = 0;
+	spin_unlock(&self->lock);
+}
+
+/*
+ * Function nsc_ircc_is_receiving (self)
+ *
+ *    Return TRUE is we are currently receiving a frame
+ *
+ */
+static int nsc_ircc_is_receiving(struct nsc_ircc_cb *self)
+{
+	unsigned long flags;
+	int status = FALSE;
+	int iobase;
+	__u8 bank;
+
+	ASSERT(self != NULL, return FALSE;);
+
+	spin_lock_irqsave(&self->lock, flags);
+
+	if (self->io.speed > 115200) {
+		iobase = self->io.fir_base;
+
+		/* Check if rx FIFO is not empty */
+		bank = inb(iobase+BSR);
+		switch_bank(iobase, BANK2);
+		if ((inb(iobase+RXFLV) & 0x3f) != 0) {
+			/* We are receiving something */
+			status =  TRUE;
+		}
+		outb(bank, iobase+BSR);
+	} else 
+		status = (self->rx_buff.state != OUTSIDE_FRAME);
+	
+	spin_unlock_irqrestore(&self->lock, flags);
+
+	return status;
+}
+
+/*
+ * Function nsc_ircc_net_init (dev)
+ *
+ *    Initialize network device
+ *
+ */
+static int nsc_ircc_net_init(struct net_device *dev)
+{
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+
+	/* Setup to be a normal IrDA network device driver */
+	irda_device_setup(dev);
+
+	/* Insert overrides below this line! */
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_open (dev)
+ *
+ *    Start the device
+ *
+ */
+static int nsc_ircc_net_open(struct net_device *dev)
+{
+	struct nsc_ircc_cb *self;
+	int iobase;
+	__u8 bank;
+	
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
+	ASSERT(dev != NULL, return -1;);
+	self = (struct nsc_ircc_cb *) dev->priv;
+	
+	ASSERT(self != NULL, return 0;);
+	
+	iobase = self->io.fir_base;
+	
+	if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, dev->name, dev)) {
+		WARNING("%s, unable to allocate irq=%d\n", driver_name, 
+			self->io.irq);
+		return -EAGAIN;
+	}
+	/*
+	 * Always allocate the DMA channel after the IRQ, and clean up on 
+	 * failure.
+	 */
+	if (request_dma(self->io.dma, dev->name)) {
+		WARNING("%s, unable to allocate dma=%d\n", driver_name, 
+			self->io.dma);
+		free_irq(self->io.irq, self);
+		return -EAGAIN;
+	}
+	
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+	
+	/* turn on interrupts */
+	switch_bank(iobase, BANK0);
+	outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	/* Ready to play! */
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* 
+	 * Open new IrLAP layer instance, now that everything should be
+	 * initialized properly 
+	 */
+	self->irlap = irlap_open(dev, &self->qos);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_close (dev)
+ *
+ *    Stop the device
+ *
+ */
+static int nsc_ircc_net_close(struct net_device *dev)
+{
+	struct nsc_ircc_cb *self;
+	int iobase;
+	__u8 bank;
+
+	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	
+	ASSERT(dev != NULL, return -1;);
+
+	self = (struct nsc_ircc_cb *) dev->priv;
+	ASSERT(self != NULL, return 0;);
+
+	/* Stop device */
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+	
+	iobase = self->io.fir_base;
+
+	disable_dma(self->io.dma);
+
+	/* Save current bank */
+	bank = inb(iobase+BSR);
+
+	/* Disable interrupts */
+	switch_bank(iobase, BANK0);
+	outb(0, iobase+IER); 
+       
+	free_irq(self->io.irq, dev);
+	free_dma(self->io.dma);
+
+	/* Restore bank register */
+	outb(bank, iobase+BSR);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Function nsc_ircc_net_ioctl (dev, rq, cmd)
+ *
+ *    Process IOCTL commands for this device
+ *
+ */
+static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct nsc_ircc_cb *self;
+	unsigned long flags;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	
+	/* Disable interrupts & save flags */
+	save_flags(flags);
+	cli();
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		nsc_ircc_change_speed(self, irq->ifr_baudrate);
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = nsc_ircc_is_receiving(self);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	restore_flags(flags);
+	
+	return ret;
+}
+
+static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
+{
+	struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv;
+	
+	return &self->stats;
+}
+
+#ifdef CONFIG_APM
+static void nsc_ircc_suspend(struct nsc_ircc_cb *self)
+{
+	MESSAGE("%s, Suspending\n", driver_name);
+
+	if (self->io.suspended)
+		return;
+
+	nsc_ircc_net_close(self->netdev);
+
+	self->io.suspended = 1;
+}
+
+static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
+{
+	struct net_device *dev = self->netdev;
+	int iobase;
+
+	if (!self->io.suspended)
+		return;
+
+	iobase = self->io.fir_base;
+
+	/* Switch to advanced mode */
+	switch_bank(iobase, BANK2);
+	outb(ECR1_EXT_SL, iobase+ECR1);
+	switch_bank(iobase, BANK0);
+
+	nsc_ircc_net_open(self->netdev);
+	
+	MESSAGE("%s, Waking up\n", driver_name);
+
+	self->io.suspended = 0;
+}
+
+static int nsc_ircc_apmproc(apm_event_t event)
+{
+	static int down = 0; /* Filter out double events */
+	int i;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (!down) {			
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					nsc_ircc_suspend(dev_self[i]);
+			}
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (down) {
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					nsc_ircc_wakeup(dev_self[i]);
+			}
+		}
+		down = 0;
+		break;
+	}
+	return 0;
+}
+#endif /* CONFIG_APM */
+
+#ifdef MODULE
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("NSC IrDA Device Driver");
+
+MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM(io,  "1-4i");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM(dma, "1-4i");
+MODULE_PARM(dongle_id, "i");
+
+int init_module(void)
+{
+	return nsc_ircc_init();
+}
+
+void cleanup_module(void)
+{
+	nsc_ircc_cleanup();
+}
+#endif /* MODULE */
+
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/nsc_fir.c linux/drivers/net/irda/nsc_fir.c
--- v2.3.41/linux/drivers/net/irda/nsc_fir.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/nsc_fir.c	Wed Dec 31 16:00:00 1969
@@ -1,1825 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      nsc_fir.c
- * Version:       1.0
- * Description:   Driver for the NSC PC'108 and PC'338 IrDA chipsets
- * Status:        Stable.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Wed Jan  5 13:59:21 2000
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
- *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
- *     Copyright (c) 1998 Actisys Corp., www.actisys.com
- *     All Rights Reserved
- *      
- *     This program is free software; you can redistribute it and/or 
- *     modify it under the terms of the GNU General Public License as 
- *     published by the Free Software Foundation; either version 2 of 
- *     the License, or (at your option) any later version.
- *  
- *     Neither Dag Brattli nor University of Tromsř admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *
- *     Notice that all functions that needs to access the chip in _any_
- *     way, must save BSR register on entry, and restore it on exit. 
- *     It is _very_ important to follow this policy!
- *
- *         __u8 bank;
- *     
- *         bank = inb(iobase+BSR);
- *  
- *         do_your_stuff_here();
- *
- *         outb(bank, iobase+BSR);
- *
- *    If you find bugs in this file, its very likely that the same bug
- *    will also be in w83977af_ir.c since the implementations are quite
- *    similar.
- *     
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-#include <linux/rtnetlink.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-#endif
-
-#include <net/irda/wrapper.h>
-#include <net/irda/irda.h>
-#include <net/irda/irmod.h>
-#include <net/irda/irlap_frame.h>
-#include <net/irda/irda_device.h>
-
-#include <net/irda/nsc_fir.h>
-
-#define CHIP_IO_EXTENT 8
-#define BROKEN_DONGLE_ID
-
-/* 
- * Define if you have multiple NSC IrDA controllers in your machine. Not
- * enabled by default since some single chips detects at multiple addresses
- */
-#undef  CONFIG_NSC_FIR_MULTIPLE 
-
-static char *driver_name = "nsc_fir";
-
-/* Module parameters */
-static int qos_mtt_bits = 0x07;  /* 1 ms or more */
-static int dongle_id = 0;
-
-static unsigned int io[]  = { 0x2f8, 0x2f8, 0x2f8, 0x2f8, 0x2f8 };
-static unsigned int io2[] = { 0x150, 0x398, 0xea, 0x15c, 0x2e };
-static unsigned int irq[] = { 3, 3, 3, 3, 3 };
-static unsigned int dma[] = { 0, 0, 0, 0, 3 };
-
-static struct nsc_fir_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL };
-
-static char *dongle_types[] = {
-	"Differential serial interface",
-	"Differential serial interface",
-	"Reserved",
-	"Reserved",
-	"Sharp RY5HD01",
-	"Reserved",
-	"Single-ended serial interface",
-	"Consumer-IR only",
-	"HP HSDL-2300, HP HSDL-3600/HSDL-3610",
-	"IBM31T1100 or Temic TFDS6000/TFDS6500",
-	"Reserved",
-	"Reserved",
-	"HP HSDL-1100/HSDL-2100",
-	"HP HSDL-1100/HSDL-2100"
-	"Supports SIR Mode only",
-	"No dongle connected",
-};
-
-/* Some prototypes */
-static int  nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, 
-			 unsigned int irq, unsigned int dma);
-#ifdef MODULE
-static int  nsc_fir_close(struct nsc_fir_cb *self);
-#endif /* MODULE */
-static int  nsc_fir_probe(int iobase, int board_addr, int irq, int dma);
-static void nsc_fir_pio_receive(struct nsc_fir_cb *self);
-static int  nsc_fir_dma_receive(struct nsc_fir_cb *self); 
-static int  nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase);
-static int  nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev);
-static int  nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev);
-static int  nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
-static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase);
-static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 baud);
-static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int  nsc_fir_is_receiving(struct nsc_fir_cb *self);
-static int  nsc_fir_read_dongle_id (int iobase);
-static void nsc_fir_init_dongle_interface (int iobase, int dongle_id);
-
-static int  nsc_fir_net_init(struct net_device *dev);
-static int  nsc_fir_net_open(struct net_device *dev);
-static int  nsc_fir_net_close(struct net_device *dev);
-static int  nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev);
-#ifdef CONFIG_APM
-static int nsc_fir_apmproc(apm_event_t event);
-#endif /* CONFIG_APM */
-/*
- * Function nsc_fir_init ()
- *
- *    Initialize chip. Just try to find out how many chips we are dealing with
- *    and where they are
- */
-int __init nsc_fir_init(void)
-{
-	int ret = -ENODEV;
-	int ioaddr;
-	int i;
-
-#ifdef CONFIG_APM
-	apm_register_callback(nsc_fir_apmproc);
-#endif /* CONFIG_APM */
-
-	for (i=0; (io[i] < 2000) && (i < 5); i++) {
-		ioaddr = io[i];
-		if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
-			continue;
-		if (nsc_fir_open(i, io[i], io2[i], irq[i], dma[i]) == 0)
-		{
-#ifdef CONFIG_NSC_FIR_MULTIPLE
-			ret = 0;
-#else
-		        return 0;
-#endif
-		}
-	}
-
-	return ret;
-}
-
-/*
- * Function nsc_fir_cleanup ()
- *
- *    Close all configured chips
- *
- */
-#ifdef MODULE
-static void nsc_fir_cleanup(void)
-{
-	int i;
-
-        IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-#ifdef CONFIG_APM
-	apm_unregister_callback(nsc_fir_apmproc);
-#endif /* CONFIG_APM */
-
-
-	for (i=0; i < 5; i++) {
-		if (dev_self[i])
-			nsc_fir_close(dev_self[i]);
-	}
-}
-#endif /* MODULE */
-
-/*
- * Function nsc_fir_open (iobase, irq)
- *
- *    Open driver instance
- *
- */
-static int 
-nsc_fir_open(int i, unsigned int iobase, unsigned int board_addr, 
-	     unsigned int irq, unsigned int dma)
-{
-	struct net_device *dev;
-	struct nsc_fir_cb *self;
-	int dongle_id;
-	int ret;
-	int err;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-	if ((dongle_id = nsc_fir_probe(iobase, board_addr, irq, dma)) == -1)
-		return -1;
-
-	/*
-	 *  Allocate new instance of the driver
-	 */
-	self = kmalloc(sizeof(struct nsc_fir_cb), GFP_KERNEL);
-	if (self == NULL) {
-		ERROR(__FUNCTION__ "(), can't allocate memory for "
-		       "control block!\n");
-		return -ENOMEM;
-	}
-	memset(self, 0, sizeof(struct nsc_fir_cb));
-	spin_lock_init(&self->lock);
-   
-	/* Need to store self somewhere */
-	dev_self[i] = self;
-
-	/* Initialize IO */
-	self->io.iobase    = iobase;
-        self->io.irq       = irq;
-        self->io.io_ext    = CHIP_IO_EXTENT;
-        self->io.dma       = dma;
-        self->io.fifo_size = 32;
-
-	/* Lock the port that we need */
-	ret = check_region(self->io.iobase, self->io.io_ext);
-	if (ret < 0) { 
-		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-		      self->io.iobase);
-		/* nsc_fir_cleanup(self->self);  */
-		return -ENODEV;
-	}
-	request_region(self->io.iobase, self->io.io_ext, driver_name);
-
-	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies(&self->qos);
-	
-	/* The only value we must override it the baudrate */
-	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
-		IR_115200|IR_576000|IR_1152000 |(IR_4000000 << 8);
-	
-	self->qos.min_turn_time.bits = qos_mtt_bits;
-	irda_qos_bits_to_value(&self->qos);
-	
-	self->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
-
-	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
-	self->rx_buff.truesize = 14384; 
-	self->tx_buff.truesize = 14384;
-
-	/* Allocate memory if needed */
-	self->rx_buff.head = (__u8 *) kmalloc(self->rx_buff.truesize,
-					      GFP_KERNEL|GFP_DMA);
-	if (self->rx_buff.head == NULL)
-		return -ENOMEM;
-	memset(self->rx_buff.head, 0, self->rx_buff.truesize);
-	
-	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
-					      GFP_KERNEL|GFP_DMA);
-	if (self->tx_buff.head == NULL) {
-		kfree(self->rx_buff.head);
-		return -ENOMEM;
-	}
-	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
-
-	self->rx_buff.in_frame = FALSE;
-	self->rx_buff.state = OUTSIDE_FRAME;
-	self->tx_buff.data = self->tx_buff.head;
-	self->rx_buff.data = self->rx_buff.head;
-	
-	/* Reset Tx queue info */
-	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
-	self->tx_fifo.tail = self->tx_buff.head;
-
-	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
-		return -ENOMEM;
-	}
-
-	dev->priv = (void *) self;
-	self->netdev = dev;
-
-	/* Override the network functions we need to use */
-	dev->init            = nsc_fir_net_init;
-	dev->hard_start_xmit = nsc_fir_hard_xmit_sir;
-	dev->open            = nsc_fir_net_open;
-	dev->stop            = nsc_fir_net_close;
-	dev->do_ioctl        = nsc_fir_net_ioctl;
-	dev->get_stats	     = nsc_fir_net_get_stats;
-
-	rtnl_lock();
-	err = register_netdevice(dev);
-	rtnl_unlock();
-	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
-		return -1;
-	}
-
-	MESSAGE("IrDA: Registered device %s\n", dev->name);
-	
-	self->io.dongle_id = dongle_id;
-	nsc_fir_init_dongle_interface(iobase, dongle_id);
-
-	return 0;
-}
-
-#ifdef MODULE
-/*
- * Function nsc_fir_close (self)
- *
- *    Close driver instance
- *
- */
-static int nsc_fir_close(struct nsc_fir_cb *self)
-{
-	int iobase;
-
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return -1;);
-
-        iobase = self->io.iobase;
-
-	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		rtnl_unlock();
-	}
-
-	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", 
-		   self->io.iobase);
-	release_region(self->io.iobase, self->io.io_ext);
-
-	if (self->tx_buff.head)
-		kfree(self->tx_buff.head);
-	
-	if (self->rx_buff.head)
-		kfree(self->rx_buff.head);
-
-	kfree(self);
-
-	return 0;
-}
-#endif /* MODULE */
-
-/*
- * Function nsc_fir_init_807 (iobase, board_addr, irq, dma)
- *
- *    Initialize the NSC '108 chip
- *
- */
-static void nsc_fir_init_807(int iobase, int board_addr, int irq, int dma)
-{
-	__u8 temp=0;
-
-	outb(2, board_addr);      /* Mode Control Register (MCTL) */
-	outb(0x00, board_addr+1); /* Disable device */
-	
-	/* Base Address and Interrupt Control Register (BAIC) */
-	outb(0, board_addr);
-	switch (iobase) {
-	case 0x3e8: outb(0x14, board_addr+1); break;
-	case 0x2e8: outb(0x15, board_addr+1); break;
-		case 0x3f8: outb(0x16, board_addr+1); break;
-	case 0x2f8: outb(0x17, board_addr+1); break;
-	default: ERROR(__FUNCTION__ "(), invalid base_address");
-	}
-	
-	/* Control Signal Routing Register (CSRT) */
-	switch (irq) {
-	case 3:  temp = 0x01; break;
-	case 4:  temp = 0x02; break;
-	case 5:  temp = 0x03; break;
-	case 7:  temp = 0x04; break;
-	case 9:  temp = 0x05; break;
-	case 11: temp = 0x06; break;
-	case 15: temp = 0x07; break;
-	default: ERROR(__FUNCTION__ "(), invalid irq");
-	}
-	outb(1, board_addr);
-	
-	switch (dma) {	
-	case 0: outb(0x08+temp, board_addr+1); break;
-	case 1: outb(0x10+temp, board_addr+1); break;
-	case 3: outb(0x18+temp, board_addr+1); break;
-	default: ERROR(__FUNCTION__ "(), invalid dma");
-	}
-	
-	outb(2, board_addr);      /* Mode Control Register (MCTL) */
-	outb(0x03, board_addr+1); /* Enable device */
-}
-
-/*
- * Function nsc_fir_init_338 (iobase, board_addr, irq, dma)
- *
- *    Initialize the NSC '338 chip. Remember that the 87338 needs two 
- *    consecutive writes to the data registers while CPU interrupts are
- *    disabled. The 97338 does not require this, but shouldn't be any
- *    harm if we do it anyway.
- */
-static void nsc_fir_init_338(int iobase, int board_addr, int irq, int dma)
-{
-	/* No init yet */
-}
-
-static int nsc_fir_find_chip(int board_addr)
-{
-	__u8 index, id;
-
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	/* Read index register */
-	index = inb(board_addr);
-	if (index == 0xff) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), no chip at 0x%03x\n", 
-			   board_addr);
-		return -1;
-	}
-
-	/* Read chip identification register (SID) for the PC97338 */
-	outb(8, board_addr);
-	id = inb(board_addr+1);
-	if ((id & 0xf0) == PC97338) {
-		MESSAGE("%s, Found NSC PC97338 chip, revision=%d\n", 
-			driver_name, id & 0x0f);
-		return PC97338;		
-	} 
-
-	/* Read device identification (DID) for the PC87108 */
-	outb(5, board_addr);
-	id = inb(board_addr+1);
-	if ((id & 0xf0) == PC87108) {
-		MESSAGE("%s, Found NSC PC87108 chip, revision=%d\n", 
-			driver_name, id & 0x0f);
-		return PC87108;
-	}
-
-	return -1;
-}
-
-/*
- * Function nsc_fir_probe (iobase, board_addr, irq, dma)
- *
- *    Returns non-negative on success.
- *
- */
-static int nsc_fir_probe(int iobase, int board_addr, int irq, int dma)
-{
-	int version;
-	__u8 chip;
-
-	chip = nsc_fir_find_chip(board_addr);
-	switch (chip) {
-	case PC87108:
-		nsc_fir_init_807(iobase, board_addr, irq, dma);
-		break;
-	case PC97338:
-		nsc_fir_init_338(iobase, board_addr, irq, dma);
-		break;
-	default:
-		/* Found no chip */
-		return -1;
-	}
-
-	/* Read the Module ID */
-	switch_bank(iobase, BANK3);
-	version = inb(iobase+MID);
-
-	/* Should be 0x2? */
-	if (0x20 != (version & 0xf0)) {
-		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
-		return -1;
-	}
-	MESSAGE("%s, Found chip at base=0x%04x\n", driver_name, board_addr);
-
-	/* Switch to advanced mode */
-	switch_bank(iobase, BANK2);
-	outb(ECR1_EXT_SL, iobase+ECR1);
-	switch_bank(iobase, BANK0);
-
-	/* Check if user has supplied the dongle id or not */
-	if (!dongle_id) {
-		dongle_id = nsc_fir_read_dongle_id(iobase);
-		
-		MESSAGE("%s, Found dongle: %s\n", driver_name,
-			dongle_types[dongle_id]);
-	} else {
-		MESSAGE("%s, Using dongle: %s\n", driver_name,
-			dongle_types[dongle_id]);
-	}
-	
-	/* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
-	switch_bank(iobase, BANK0);	
-	outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
-	
-	/* Set FIFO size to 32 */
-	switch_bank(iobase, BANK2);
-	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
-
-	/* IRCR2: FEND_MD is set */
-	switch_bank(iobase, BANK5);
- 	outb(0x2a, iobase+4);
-
-	/* Make sure that some defaults are OK */
-	switch_bank(iobase, BANK6);
-	outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
-	outb(0x0a, iobase+1); /* Set MIR pulse width */
-	outb(0x0d, iobase+2); /* Set SIR pulse width */
-	outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
-
-	MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
-
-	/* Enable receive interrupts */
-	switch_bank(iobase, BANK0);
-	outb(IER_RXHDL_IE, iobase+IER);
-
-	return dongle_id;
-}
-
-/*
- * Function nsc_fir_read_dongle_id (void)
- *
- * Try to read dongle indentification. This procedure needs to be executed
- * once after power-on/reset. It also needs to be used whenever you suspect
- * that the user may have plugged/unplugged the IrDA Dongle.
- * 
- */
-static int nsc_fir_read_dongle_id (int iobase)
-{
-	int dongle_id;
-	__u8 bank;
-
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	bank = inb(iobase+BSR);
-
-	/* Select Bank 7 */
-	switch_bank(iobase, BANK7);
-	
-	/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
-	outb(0x00, iobase+7);
-	
-	/* ID0, 1, and 2 are pulled up/down very slowly */
-	udelay(50);
-	
-	/* IRCFG1: read the ID bits */
-	dongle_id = inb(iobase+4) & 0x0f;
-
-#ifdef BROKEN_DONGLE_ID
-	if (dongle_id == 0x0a)
-		dongle_id = 0x09;
-#endif
-	
-	/* Go back to  bank 0 before returning */
-	switch_bank(iobase, BANK0);
-
-	outb(bank, iobase+BSR);
-
-	return dongle_id;
-}
-
-/*
- * Function nsc_fir_init_dongle_interface (iobase, dongle_id)
- *
- *     This function initializes the dongle for the transceiver that is
- *     used. This procedure needs to be executed once after
- *     power-on/reset. It also needs to be used whenever you suspect that
- *     the dongle is changed. 
- */
-static void nsc_fir_init_dongle_interface (int iobase, int dongle_id)
-{
-	int bank;
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-
-	/* Select Bank 7 */
-	switch_bank(iobase, BANK7);
-	
-	/* IRCFG4: set according to dongle_id */
-	switch (dongle_id) {
-	case 0x00: /* same as */
-	case 0x01: /* Differential serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x02: /* same as */
-	case 0x03: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x04: /* Sharp RY5HD01 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x05: /* Reserved, but this is what the Thinkpad reports */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x06: /* Single-ended serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x07: /* Consumer-IR only */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
-		outb_p(0x28, iobase+7); /* Set irsl[0-2] as output */
-		break;
-	case 0x0A: /* same as */
-	case 0x0B: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x0C: /* same as */
-	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
-		/* 
-		 * Set irsl0 as input, irsl[1-2] as output, and separate 
-		 * inputs are used for SIR and MIR/FIR 
-		 */
-		outb(0x48, iobase+7); 
-		break;
-	case 0x0E: /* Supports SIR Mode only */
-		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
-		break;
-	case 0x0F: /* No dongle connected */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
-			   dongle_types[dongle_id]); 
-
-		switch_bank(iobase, BANK0);
-		outb(0x62, iobase+MCR);
-		break;
-	default: 
-		IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", 
-			   dongle_id);
-	}
-	
-	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
-	outb(0x00, iobase+4);
-
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-	
-} /* set_up_dongle_interface */
-
-/*
- * Function nsc_fir_change_dongle_speed (iobase, speed, dongle_id)
- *
- *    Change speed of the attach dongle
- *
- */
-static void nsc_fir_change_dongle_speed(int iobase, int speed, int dongle_id)
-{
-	unsigned long flags;
-	__u8 bank;
-
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-
-	/* Select Bank 7 */
-	switch_bank(iobase, BANK7);
-	
-	/* IRCFG1: set according to dongle_id */
-	switch (dongle_id) {
-	case 0x00: /* same as */
-	case 0x01: /* Differential serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x02: /* same as */
-	case 0x03: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x04: /* Sharp RY5HD01 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
-			   dongle_types[dongle_id]); 
-	case 0x05: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x06: /* Single-ended serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x07: /* Consumer-IR only */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not supported yet\n",
-			   dongle_types[dongle_id]); 
-	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
-		switch_bank(iobase, BANK7);
-		outb_p(0x01, iobase+4);
-
-		if (speed == 4000000) {
-			save_flags(flags);
-			cli();
-			outb(0x81, iobase+4);
-			outb(0x80, iobase+4);
-			restore_flags(flags);
-		} else
-			outb_p(0x00, iobase+4);
-		break;
-	case 0x0A: /* same as */
-	case 0x0B: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
-		break;
-	case 0x0C: /* same as */
-	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
-		break;
-	case 0x0E: /* Supports SIR Mode only */
-		break;
-	case 0x0F: /* No dongle connected */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]);
-
-		switch_bank(iobase, BANK0); 
-		outb(0x62, iobase+MCR);
-		break;
-	default: 
-		IRDA_DEBUG(0, __FUNCTION__ "(), invalid data_rate\n");
-	}
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-}
-
-/*
- * Function nsc_fir_change_speed (self, baud)
- *
- *    Change the speed of the device
- *
- */
-static void nsc_fir_change_speed(struct nsc_fir_cb *self, __u32 speed)
-{
-	struct net_device *dev = self->netdev;
-	__u8 mcr = MCR_SIR;
-	int iobase; 
-	__u8 bank;
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d\n", speed);
-
-	ASSERT(self != NULL, return;);
-
-	iobase = self->io.iobase;
-
-	/* Update accounting for new speed */
-	self->io.speed = speed;
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-
-	/* Disable interrupts */
-	switch_bank(iobase, BANK0);
-	outb(0, iobase+IER);
-
-	/* Select Bank 2 */
-	switch_bank(iobase, BANK2);
-
-	outb(0x00, iobase+BGDH);
-	switch (speed) {
-	case 9600:   outb(0x0c, iobase+BGDL); break;
-	case 19200:  outb(0x06, iobase+BGDL); break;
-	case 38400:  outb(0x03, iobase+BGDL); break;
-	case 57600:  outb(0x02, iobase+BGDL); break;
-	case 115200: outb(0x01, iobase+BGDL); break;
-	case 576000:
-		switch_bank(iobase, BANK5);
-		
-		/* IRCR2: MDRS is set */
-		outb(inb(iobase+4) | 0x04, iobase+4);
-	       
-		mcr = MCR_MIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
-		break;
-	case 1152000:
-		mcr = MCR_MIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
-		break;
-	case 4000000:
-		mcr = MCR_FIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
-		break;
-	default:
-		mcr = MCR_FIR;
-		IRDA_DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", 
-			   speed);
-		break;
-	}
-
-	/* Set appropriate speed mode */
-	switch_bank(iobase, BANK0);
-	outb(mcr | MCR_TX_DFR, iobase+MCR);
-
-	/* Give some hits to the transceiver */
-	nsc_fir_change_dongle_speed(iobase, speed, self->io.dongle_id);
-
-	/* Set FIFO threshold to TX17, RX16 */
-	switch_bank(iobase, BANK0);
-	outb(0x00, iobase+FCR);
-	outb(FCR_FIFO_EN, iobase+FCR);
-	outb(FCR_RXTH|     /* Set Rx FIFO threshold */
-	     FCR_TXTH|     /* Set Tx FIFO threshold */
-	     FCR_TXSR|     /* Reset Tx FIFO */
-	     FCR_RXSR|     /* Reset Rx FIFO */
-	     FCR_FIFO_EN,  /* Enable FIFOs */
-	     iobase+FCR);
-	
-	/* Set FIFO size to 32 */
-	switch_bank(iobase, BANK2);
-	outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
-	
-	self->netdev->tbusy = 0;
-	
-	/* Enable some interrupts so we can receive frames */
-	switch_bank(iobase, BANK0); 
-	if (speed > 115200) {
-		/* Install FIR xmit handler */
-		dev->hard_start_xmit = nsc_fir_hard_xmit_fir;
-		outb(IER_SFIF_IE, iobase+IER);
-		nsc_fir_dma_receive(self);
-	} else {
-		/* Install SIR xmit handler */
-		dev->hard_start_xmit = nsc_fir_hard_xmit_sir;
-		outb(IER_RXHDL_IE, iobase+IER);
-	}
-    	
-	/* Restore BSR */
-	outb(bank, iobase+BSR);
-}
-
-/*
- * Function nsc_fir_hard_xmit (skb, dev)
- *
- *    Transmit the frame!
- *
- */
-static int nsc_fir_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
-{
-	struct nsc_fir_cb *self;
-	unsigned long flags;
-	int iobase;
-	__u32 speed;
-	__u8 bank;
-	
-	self = (struct nsc_fir_cb *) dev->priv;
-
-	ASSERT(self != NULL, return 0;);
-
-	iobase = self->io.iobase;
-
-	/* Lock transmit buffer */
-	if (irda_lock((void *) &dev->tbusy) == FALSE)
-		return -EBUSY;
-	
-	/* Check if we need to change the speed */
-	if ((speed = irda_get_speed(skb)) != self->io.speed)
-		self->new_speed = speed;
-	
-	spin_lock_irqsave(&self->lock, flags);
-	
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-	
-	self->tx_buff.data = self->tx_buff.head;
-	
-	self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, 
-					   self->tx_buff.truesize);
-	
-	/* Add interrupt on tx low level (will fire immediately) */
-	switch_bank(iobase, BANK0);
-	outb(IER_TXLDL_IE, iobase+IER);
-	
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-
-	spin_unlock_irqrestore(&self->lock, flags);
-
-	dev_kfree_skb(skb);
-
-	return 0;
-}
-
-static int nsc_fir_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
-{
-	struct nsc_fir_cb *self;
-	unsigned long flags;
-	int iobase;
-	__u32 speed;
-	__u8 bank;
-	int mtt, diff;
-	
-	self = (struct nsc_fir_cb *) dev->priv;
-
-	ASSERT(self != NULL, return 0;);
-
-	iobase = self->io.iobase;
-
-	/* Lock transmit buffer */
-	if (irda_lock((void *) &dev->tbusy) == FALSE)
-		return -EBUSY;
-
-	/* Check if we need to change the speed */
-	if ((speed = irda_get_speed(skb)) != self->io.speed)
-		self->new_speed = speed;
-
-	spin_lock_irqsave(&self->lock, flags);
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-
-	/* Register and copy this frame to DMA memory */
-	self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
-	self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
-	self->tx_fifo.tail += skb->len;
-
-	memcpy(self->tx_fifo.queue[self->tx_fifo.free].start, skb->data, 
-	       skb->len);
-	
-	self->tx_fifo.len++;
-	self->tx_fifo.free++;
-
-	/* Start transmit only if there is currently no transmit going on */
-	if (self->tx_fifo.len == 1) {
-		mtt = irda_get_mtt(skb);
-		if (mtt) {
-			/* Check how much time we have used already */
-			do_gettimeofday(&self->now);
-			diff = self->now.tv_usec - self->stamp.tv_usec;
-			if (diff < 0) 
-				diff += 1000000;
-			
-			/* Check if the mtt is larger than the time we have
-			 * already used by all the protocol processing
-			 */
-			if (mtt > diff) {
-				mtt -= diff;
-				if (mtt > 125) {
-					/* Adjust for timer resolution */
-					mtt = mtt / 125 + 1;
-					
-					/* Setup timer */
-					switch_bank(iobase, BANK4);
-					outb(mtt & 0xff, iobase+TMRL);
-					outb((mtt >> 8) & 0x0f, iobase+TMRH);
-					
-					/* Start timer */
-					outb(IRCR1_TMR_EN, iobase+IRCR1);
-					self->io.direction = IO_XMIT;
-					
-					/* Enable timer interrupt */
-					switch_bank(iobase, BANK0);
-					outb(IER_TMR_IE, iobase+IER);
-					
-					/* Timer will take care of the rest */
-					goto out; 
-				} else
-					udelay(mtt);
-			}
-		}
-		
-		/* Enable DMA interrupt */
-		switch_bank(iobase, BANK0);
-		outb(IER_DMA_IE, iobase+IER);
-		nsc_fir_dma_xmit(self, iobase);
-	}
-	/* Not busy transmitting anymore if window is not full */
-	if (self->tx_fifo.len < MAX_WINDOW)
-		dev->tbusy = 0;
- out:
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-
-	spin_unlock_irqrestore(&self->lock, flags);
-
-	dev_kfree_skb(skb);
-
-	return 0;
-}
-
-/*
- * Function nsc_fir_dma_xmit (self, iobase)
- *
- *    Transmit data using DMA
- *
- */
-static void nsc_fir_dma_xmit(struct nsc_fir_cb *self, int iobase)
-{
-	int bsr;
-
-	/* Save current bank */
-	bsr = inb(iobase+BSR);
-
-	/* Disable DMA */
-	switch_bank(iobase, BANK0);
-	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-	
-	self->io.direction = IO_XMIT;
-	
-	/* Choose transmit DMA channel  */ 
-	switch_bank(iobase, BANK2);
-	outb(ECR1_DMASWP|ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
-	
-	setup_dma(self->io.dma, 
-		  self->tx_fifo.queue[self->tx_fifo.ptr].start, 
-		  self->tx_fifo.queue[self->tx_fifo.ptr].len, 
-		  DMA_TX_MODE);
-
-	/* Enable DMA and SIR interaction pulse */
- 	switch_bank(iobase, BANK0);	
-	outb(inb(iobase+MCR)|MCR_TX_DFR|MCR_DMA_EN|MCR_IR_PLS, iobase+MCR);
-
-	/* Restore bank register */
-	outb(bsr, iobase+BSR);
-}
-
-/*
- * Function nsc_fir_pio_xmit (self, iobase)
- *
- *    Transmit data using PIO. Returns the number of bytes that actually
- *    got transfered
- *
- */
-static int nsc_fir_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
-{
-	int actual = 0;
-	__u8 bank;
-	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-
-	switch_bank(iobase, BANK0);
-	if (!(inb_p(iobase+LSR) & LSR_TXEMP)) {
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), warning, FIFO not empty yet!\n");
-
-		fifo_size -= 17;
-	}
-
-	/* Fill FIFO with current frame */
-	while ((fifo_size-- > 0) && (actual < len)) {
-		/* Transmit next byte */
-		outb(buf[actual++], iobase+TXD);
-	}
-        
-	IRDA_DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-		   fifo_size, actual, len);
-	
-	/* Restore bank */
-	outb(bank, iobase+BSR);
-
-	return actual;
-}
-
-/*
- * Function nsc_fir_dma_xmit_complete (self)
- *
- *    The transfer of a frame in finished. This function will only be called 
- *    by the interrupt handler
- *
- */
-static int nsc_fir_dma_xmit_complete(struct nsc_fir_cb *self)
-{
-	int iobase;
-	__u8 bank;
-	int ret = TRUE;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-	iobase = self->io.iobase;
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-
-	/* Disable DMA */
-	switch_bank(iobase, BANK0);
-        outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-	
-	/* Check for underrrun! */
-	if (inb(iobase+ASCR) & ASCR_TXUR) {
-		self->stats.tx_errors++;
-		self->stats.tx_fifo_errors++;
-		
-		/* Clear bit, by writing 1 into it */
-		outb(ASCR_TXUR, iobase+ASCR);
-	} else {
-		self->stats.tx_packets++;
-		self->stats.tx_bytes += self->tx_buff.len;
-	}
-	
-	if (self->new_speed) {
-		nsc_fir_change_speed(self, self->new_speed);
-		self->new_speed = 0;
-	}
-
-	/* Finished with this frame, so prepare for next */
-	self->tx_fifo.ptr++;
-	self->tx_fifo.len--;
-
-	/* Any frames to be sent back-to-back? */
-	if (self->tx_fifo.len) {
-		nsc_fir_dma_xmit(self, iobase);
-		
-		/* Not finished yet! */
-		ret = FALSE;
-	}
-
-	/* Not busy transmitting anymore */
-	self->netdev->tbusy = 0;
-
-	/* Tell the network layer, that we can accept more frames */
-	mark_bh(NET_BH);
-
-	/* Restore bank */
-	outb(bank, iobase+BSR);
-	
-	return ret;
-}
-
-/*
- * Function nsc_fir_dma_receive (self)
- *
- *    Get ready for receiving a frame. The device will initiate a DMA
- *    if it starts to receive a frame.
- *
- */
-static int nsc_fir_dma_receive(struct nsc_fir_cb *self) 
-{
-	int iobase;
-	__u8 bsr;
-
-	ASSERT(self != NULL, return -1;);
-
-	iobase = self->io.iobase;
-
-	/* Reset Tx FIFO info */
-	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
-	self->tx_fifo.tail = self->tx_buff.head;
-
-	/* Save current bank */
-	bsr = inb(iobase+BSR);
-
-	/* Disable DMA */
-	switch_bank(iobase, BANK0);
-	outb(inb(iobase+MCR) & ~MCR_DMA_EN, iobase+MCR);
-
-	/* Choose DMA Rx, DMA Fairness, and Advanced mode */
-	switch_bank(iobase, BANK2);
-	outb(ECR1_DMANF|ECR1_EXT_SL, iobase+ECR1);
-
-	self->io.direction = IO_RECV;
-	self->rx_buff.data = self->rx_buff.head;
-	
-	/* Reset Rx FIFO. This will also flush the ST_FIFO */
-	switch_bank(iobase, BANK0);
-	outb(FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
-	self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0;
-	
-	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
-		  DMA_RX_MODE);
-
-	/* Enable DMA */
-	switch_bank(iobase, BANK0);
-	outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
-
-	/* Restore bank register */
-	outb(bsr, iobase+BSR);
-	
-	return 0;
-}
-
-/*
- * Function nsc_fir_dma_receive_complete (self)
- *
- *    Finished with receiving frames
- *
- *    
- */
-static int nsc_fir_dma_receive_complete(struct nsc_fir_cb *self, int iobase)
-{
-	struct sk_buff *skb;
-	struct st_fifo *st_fifo;
-	__u8 bank;
-	__u8 status;
-	int len;
-
-	st_fifo = &self->st_fifo;
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-	
-	/* Read status FIFO */
-	switch_bank(iobase, BANK5);
-	while ((status = inb(iobase+FRM_ST)) & FRM_ST_VLD) {
-		st_fifo->entries[st_fifo->tail].status = status;
-
-		st_fifo->entries[st_fifo->tail].len  = inb(iobase+RFLFL);
-		st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8;
-		
-		st_fifo->tail++;
-		st_fifo->len++;
-	}
-	/* Try to process all entries in status FIFO */
-	while (st_fifo->len) {
-		/* Get first entry */
-		status = st_fifo->entries[st_fifo->head].status;
-		len    = st_fifo->entries[st_fifo->head].len;
-		st_fifo->head++;
-		st_fifo->len--;
-
-		/* Check for errors */
-		if (status & FRM_ST_ERR_MSK) {
-			if (status & FRM_ST_LOST_FR) {
-				/* Add number of lost frames to stats */
-				self->stats.rx_errors += len;	
-			} else {
-				/* Skip frame */
-				self->stats.rx_errors++;
-				
-				self->rx_buff.data += len;
-			
-				if (status & FRM_ST_MAX_LEN)
-					self->stats.rx_length_errors++;
-				
-				if (status & FRM_ST_PHY_ERR) 
-					self->stats.rx_frame_errors++;
-				
-				if (status & FRM_ST_BAD_CRC) 
-					self->stats.rx_crc_errors++;
-			}
-			/* The errors below can be reported in both cases */
-			if (status & FRM_ST_OVR1)
-				self->stats.rx_fifo_errors++;		       
-			
-			if (status & FRM_ST_OVR2)
-				self->stats.rx_fifo_errors++;
-		} else {
-			/* Check if we have transfered all data to memory */
-			switch_bank(iobase, BANK0);
-			if (inb(iobase+LSR) & LSR_RXDA) {
-				/* Put this entry back in fifo */
-				st_fifo->head--;
-				st_fifo->len++;
-				st_fifo->entries[st_fifo->head].status = status;
-				st_fifo->entries[st_fifo->head].len = len;
-				
-				/* Restore bank register */
-				outb(bank, iobase+BSR);
-				
-				return FALSE; 	/* I'll be back! */
-			}
-
-			/* 
-			 * Remember when we received this frame, so we can
-			 * reduce the min turn time a bit since we will know
-			 * how much time we have used for protocol processing
-			 */
-			do_gettimeofday(&self->stamp);
-
-			skb = dev_alloc_skb(len+1);
-			if (skb == NULL)  {
-				WARNING(__FUNCTION__ "(), memory squeeze, "
-					"dropping frame.\n");
-				
-				/* Restore bank register */
-				outb(bank, iobase+BSR);
-				
-				return FALSE;
-			}
-			
-			/* Make sure IP header gets aligned */
-			skb_reserve(skb, 1); 
-
-			/* Copy frame without CRC */
-			if (self->io.speed < 4000000) {
-				skb_put(skb, len-2);
-				memcpy(skb->data, self->rx_buff.data, len-2);
-			} else {
-				skb_put(skb, len-4);
-				memcpy(skb->data, self->rx_buff.data, len-4);
-			}
-
-			/* Move to next frame */
-			self->rx_buff.data += len;
-			self->stats.rx_packets++;
-
-			skb->dev = self->netdev;
-			skb->mac.raw  = skb->data;
-			skb->protocol = htons(ETH_P_IRDA);
-			netif_rx(skb);
-		}
-	}
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-
-	return TRUE;
-}
-
-/*
- * Function nsc_fir_pio_receive (self)
- *
- *    Receive all data in receiver FIFO
- *
- */
-static void nsc_fir_pio_receive(struct nsc_fir_cb *self) 
-{
-	__u8 byte = 0x00;
-	int iobase;
-
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(self != NULL, return;);
-	
-	iobase = self->io.iobase;
-	
-	/*  Receive all characters in Rx FIFO */
-	do {
-		byte = inb(iobase+RXD);
-		async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, 
-				  byte);
-	} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */	
-}
-
-/*
- * Function nsc_fir_sir_interrupt (self, eir)
- *
- *    Handle SIR interrupt
- *
- */
-static __u8 nsc_fir_sir_interrupt(struct nsc_fir_cb *self, int eir)
-{
-	int actual;
-	__u8 new_ier = 0;
-
-	/* Check if transmit FIFO is low on data */
-	if (eir & EIR_TXLDL_EV) {
-		/* Write data left in transmit buffer */
-		actual = nsc_fir_pio_write(self->io.iobase, 
-					   self->tx_buff.data, 
-					   self->tx_buff.len, 
-					   self->io.fifo_size);
-		self->tx_buff.data += actual;
-		self->tx_buff.len  -= actual;
-		
-		self->io.direction = IO_XMIT;
-
-		/* Check if finished */
-		if (self->tx_buff.len > 0)
-			new_ier |= IER_TXLDL_IE;
-		else { 
-			self->netdev->tbusy = 0; /* Unlock */
-			self->stats.tx_packets++;
-			
-		        mark_bh(NET_BH);	
-
-			new_ier |= IER_TXEMP_IE;
-		}
-			
-	}
-	/* Check if transmission has completed */
-	if (eir & EIR_TXEMP_EV) {
-		/* Check if we need to change the speed? */
-		if (self->new_speed) {
-			IRDA_DEBUG(2, __FUNCTION__ "(), Changing speed!\n");
-			nsc_fir_change_speed(self, self->new_speed);
-			self->new_speed = 0;
-		}
-
-		/* Turn around and get ready to receive some data */
-		self->io.direction = IO_RECV;
-		new_ier |= IER_RXHDL_IE;
-	}
-
-	/* Rx FIFO threshold or timeout */
-	if (eir & EIR_RXHDL_EV) {
-		nsc_fir_pio_receive(self);
-
-		/* Keep receiving */
-		new_ier |= IER_RXHDL_IE;
-	}
-	return new_ier;
-}
-
-/*
- * Function nsc_fir_fir_interrupt (self, eir)
- *
- *    Handle MIR/FIR interrupt
- *
- */
-static __u8 nsc_fir_fir_interrupt(struct nsc_fir_cb *self, int iobase, int eir)
-{
-	__u8 new_ier = 0;
-	__u8 bank;
-
-	bank = inb(iobase+BSR);
-	
-	/* Status event, or end of frame detected in FIFO */
-	if (eir & (EIR_SFIF_EV|EIR_LS_EV)) {
-		if (nsc_fir_dma_receive_complete(self, iobase)) {
-
-			/* Wait for next status FIFO interrupt */
-			new_ier |= IER_SFIF_IE;
-		} else {
-			/* DMA not finished yet */
-
-			/* Set timer value, resolution 125 us */
-			switch_bank(iobase, BANK4);
-			outb(0x0f, iobase+TMRL); /* 125 us * 15 */
-			outb(0x00, iobase+TMRH);
-
-			/* Start timer */
-			outb(IRCR1_TMR_EN, iobase+IRCR1);
-
-			new_ier |= IER_TMR_IE;
-		}
-	} else if (eir & EIR_TMR_EV) { /* Timer finished */
-		/* Disable timer */
-		switch_bank(iobase, BANK4);
-		outb(0, iobase+IRCR1);
-
-		/* Clear timer event */
-		switch_bank(iobase, BANK0);
-		outb(ASCR_CTE, iobase+ASCR);
-
-		/* Check if this is a TX timer interrupt */
-		if (self->io.direction == IO_XMIT) {
-			nsc_fir_dma_xmit(self, iobase);
-
-			/*  Interrupt on DMA */
-			new_ier |= IER_DMA_IE;
-		} else {
-			/* Check if DMA has now finished */
-			nsc_fir_dma_receive_complete(self, iobase);
-
-			new_ier |= IER_SFIF_IE;
-		}
-	} else if (eir & EIR_DMA_EV) { /* Finished with transmission */
-		if (nsc_fir_dma_xmit_complete(self)) {		
-			/* Check if there are more frames to be transmitted */
-			if (irda_device_txqueue_empty(self->netdev)) {
-				/* Prepare for receive */
-				nsc_fir_dma_receive(self);
-			
-				new_ier = IER_LS_IE|IER_SFIF_IE;
-			}
-		} else {
-			/*  Not finished yet, so interrupt on DMA again */
-			new_ier |= IER_DMA_IE;
-		}
-	}
-	outb(bank, iobase+BSR);
-
-	return new_ier;
-}
-
-/*
- * Function nsc_fir_interrupt (irq, dev_id, regs)
- *
- *    An interrupt from the chip has arrived. Time to do some work
- *
- */
-static void nsc_fir_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct nsc_fir_cb *self;
-	__u8 bsr, eir, ier;
-	int iobase;
-
-	if (!dev) {
-		printk(KERN_WARNING "%s: irq %d for unknown device.\n", 
-		       driver_name, irq);
-		return;
-	}
-	self = (struct nsc_fir_cb *) dev->priv;
-
-	spin_lock(&self->lock);	
-	dev->interrupt = 1;
-
-	iobase = self->io.iobase;
-
-	bsr = inb(iobase+BSR); 	/* Save current bank */
-
-	switch_bank(iobase, BANK0);	
-	ier = inb(iobase+IER); 
-	eir = inb(iobase+EIR) & ier; /* Mask out the interesting ones */ 
-
-	outb(0, iobase+IER); /* Disable interrupts */
-	
-	if (eir) {
-		/* Dispatch interrupt handler for the current speed */
-		if (self->io.speed > 115200)
-			ier = nsc_fir_fir_interrupt(self, iobase, eir);
-		else
-			ier = nsc_fir_sir_interrupt(self, eir);
-	}
-
-	outb(ier, iobase+IER);   /* Restore interrupts */
-	outb(bsr, iobase+BSR);   /* Restore bank register */
-
-	dev->interrupt = 0;
-	spin_unlock(&self->lock);
-}
-
-/*
- * Function nsc_fir_is_receiving (self)
- *
- *    Return TRUE is we are currently receiving a frame
- *
- */
-static int nsc_fir_is_receiving(struct nsc_fir_cb *self)
-{
-	int status = FALSE;
-	int iobase;
-	__u8 bank;
-
-	ASSERT(self != NULL, return FALSE;);
-
-	if (self->io.speed > 115200) {
-		iobase = self->io.iobase;
-
-		/* Check if rx FIFO is not empty */
-		bank = inb(iobase+BSR);
-		switch_bank(iobase, BANK2);
-		if ((inb(iobase+RXFLV) & 0x3f) != 0) {
-			/* We are receiving something */
-			status =  TRUE;
-		}
-		outb(bank, iobase+BSR);
-	} else 
-		status = (self->rx_buff.state != OUTSIDE_FRAME);
-	
-	return status;
-}
-
-/*
- * Function nsc_fir_net_init (dev)
- *
- *    Initialize network device
- *
- */
-static int nsc_fir_net_init(struct net_device *dev)
-{
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-
-	/* Setup to be a normal IrDA network device driver */
-	irda_device_setup(dev);
-
-	/* Insert overrides below this line! */
-
-	return 0;
-}
-
-/*
- * Function nsc_fir_net_open (dev)
- *
- *    Start the device
- *
- */
-static int nsc_fir_net_open(struct net_device *dev)
-{
-	struct nsc_fir_cb *self;
-	int iobase;
-	__u8 bank;
-	
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-	
-	ASSERT(dev != NULL, return -1;);
-	self = (struct nsc_fir_cb *) dev->priv;
-	
-	ASSERT(self != NULL, return 0;);
-	
-	iobase = self->io.iobase;
-
-	if (request_irq(self->io.irq, nsc_fir_interrupt, 0, dev->name, 
-			(void *) dev)) 
-	{
-		return -EAGAIN;
-	}
-	/*
-	 * Always allocate the DMA channel after the IRQ, and clean up on 
-	 * failure.
-	 */
-	if (request_dma(self->io.dma, dev->name)) {
-		free_irq(self->io.irq, self);
-		return -EAGAIN;
-	}
-	
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-	
-	/* turn on interrupts */
-	switch_bank(iobase, BANK0);
-	outb(IER_LS_IE | IER_RXHDL_IE, iobase+IER);
-
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-
-	/* Ready to play! */
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-
-	/* 
-	 * Open new IrLAP layer instance, now that everything should be
-	 * initialized properly 
-	 */
-	self->irlap = irlap_open(dev, &self->qos);
-
-	MOD_INC_USE_COUNT;
-
-	return 0;
-}
-
-/*
- * Function nsc_fir_net_close (dev)
- *
- *    Stop the device
- *
- */
-static int nsc_fir_net_close(struct net_device *dev)
-{
-	struct nsc_fir_cb *self;
-	int iobase;
-	__u8 bank;
-
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
-	
-	ASSERT(dev != NULL, return -1;);
-	self = (struct nsc_fir_cb *) dev->priv;
-	
-	ASSERT(self != NULL, return 0;);
-
-	/* Stop device */
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	/* Stop and remove instance of IrLAP */
-	if (self->irlap)
-		irlap_close(self->irlap);
-	self->irlap = NULL;
-	
-	iobase = self->io.iobase;
-
-	disable_dma(self->io.dma);
-
-	/* Save current bank */
-	bank = inb(iobase+BSR);
-
-	/* Disable interrupts */
-	switch_bank(iobase, BANK0);
-	outb(0, iobase+IER); 
-       
-	free_irq(self->io.irq, dev);
-	free_dma(self->io.dma);
-
-	/* Restore bank register */
-	outb(bank, iobase+BSR);
-
-	MOD_DEC_USE_COUNT;
-
-	return 0;
-}
-
-/*
- * Function nsc_fir_net_ioctl (dev, rq, cmd)
- *
- *    Process IOCTL commands for this device
- *
- */
-static int nsc_fir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct if_irda_req *irq = (struct if_irda_req *) rq;
-	struct nsc_fir_cb *self;
-	unsigned long flags;
-	int ret = 0;
-
-	ASSERT(dev != NULL, return -1;);
-
-	self = dev->priv;
-
-	ASSERT(self != NULL, return -1;);
-
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
-	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
-	
-	switch (cmd) {
-	case SIOCSBANDWIDTH: /* Set bandwidth */
-		nsc_fir_change_speed(self, irq->ifr_baudrate);
-		break;
-	case SIOCSMEDIABUSY: /* Set media busy */
-		irda_device_set_media_busy(self->netdev, TRUE);
-		break;
-	case SIOCGRECEIVING: /* Check if we are receiving right now */
-		irq->ifr_receiving = nsc_fir_is_receiving(self);
-		break;
-	default:
-		ret = -EOPNOTSUPP;
-	}
-	
-	restore_flags(flags);
-	
-	return ret;
-}
-
-static struct net_device_stats *nsc_fir_net_get_stats(struct net_device *dev)
-{
-	struct nsc_fir_cb *self = (struct nsc_fir_cb *) dev->priv;
-	
-	return &self->stats;
-}
-
-#ifdef CONFIG_APM
-static void nsc_fir_suspend(struct nsc_fir_cb *self)
-{
-	int i = 10;
-
-	MESSAGE("%s, Suspending\n", driver_name);
-
-	if (self->suspend)
-		return;
-
-	self->suspend = 1;
-}
-
-
-static void nsc_fir_wakeup(struct nsc_fir_cb *self)
-{
-	struct net_device *dev = self->netdev;
-	unsigned long flags;
-
-	if (!self->suspend)
-		return;
-
-	save_flags(flags);
-	cli();
-
-	restore_flags(flags);
-	MESSAGE("%s, Waking up\n", driver_name);
-}
-
-static int nsc_fir_apmproc(apm_event_t event)
-{
-	static int down = 0;          /* Filter out double events */
-	int i;
-
-	switch (event) {
-	case APM_SYS_SUSPEND:
-	case APM_USER_SUSPEND:
-		if (!down) {			
-			for (i = 0; i < 4; i++) {
-				if (dev_self[i])
-					nsc_fir_suspend(dev_self[i]);
-			}
-		}
-		down = 1;
-		break;
-	case APM_NORMAL_RESUME:
-	case APM_CRITICAL_RESUME:
-		if (down) {
-			for (i = 0; i < 4; i++) {
-				if (dev_self[i])
-					nsc_fir_wakeup(dev_self[i]);
-			}
-		}
-		down = 0;
-		break;
-	}
-	return 0;
-}
-#endif /* CONFIG_APM */
-
-#ifdef MODULE
-MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("NSC FIR IrDA Device Driver");
-
-MODULE_PARM(qos_mtt_bits, "i");
-MODULE_PARM(io, "1-4i");
-MODULE_PARM(io2, "1-4i");
-MODULE_PARM(irq, "1-4i");
-MODULE_PARM(dongle_id, "i");
-
-int init_module(void)
-{
-	return nsc_fir_init();
-}
-
-void cleanup_module(void)
-{
-	nsc_fir_cleanup();
-}
-#endif /* MODULE */
-
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/smc-ircc.c linux/drivers/net/irda/smc-ircc.c
--- v2.3.41/linux/drivers/net/irda/smc-ircc.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/smc-ircc.c	Mon Jan 31 23:43:51 2000
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      smc-ircc.c
- * Version:       0.3
+ * Version:       0.4
  * Description:   Driver for the SMC Infrared Communications Controller
  * Status:        Experimental.
  * Author:        Thomas Davis (tadavis@jps.net)
  * Created at:    
- * Modified at:   Wed Jan  5 12:38:06 2000
+ * Modified at:   Fri Jan 21 09:41:08 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999-2000 Dag Brattli
@@ -28,11 +28,12 @@
  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
  *     MA 02111-1307 USA
  *
- *     SIO's: SMC FDC37N869, FDC37C669
+ *     SIO's: SMC FDC37N869, FDC37C669, FDC37N958
  *     Applicable Models : Fujitsu Lifebook 635t, Sony PCG-505TX
  *
  ********************************************************************/
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -44,11 +45,16 @@
 #include <linux/malloc.h>
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
+#include <linux/serial_reg.h>
 
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
 #include <net/irda/wrapper.h>
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -62,10 +68,10 @@
 
 #define CHIP_IO_EXTENT 8
 
-static unsigned int io[]  = { 0x2e8, 0x140, 0x118, 0x240 }; 
-static unsigned int io2[] = { 0x2f8, 0x3e8, 0x2e8, 0x3e8 };
+static unsigned int io[]  = { ~0, ~0 }; 
+static unsigned int io2[] = { 0, 0 };
 
-static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL};
+static struct ircc_cb *dev_self[] = { NULL, NULL};
 
 /* Some prototypes */
 static int  ircc_open(int i, unsigned int iobase, unsigned int board_addr);
@@ -73,17 +79,30 @@
 static int  ircc_close(struct ircc_cb *self);
 #endif /* MODULE */
 static int  ircc_probe(int iobase, int board_addr);
-static int  ircc_probe_smc(int *ioaddr, int *ioaddr2);
-static int  ircc_dma_receive(struct ircc_cb *self); 
-static int  ircc_dma_receive_complete(struct ircc_cb *self, int iobase);
+static int  ircc_probe_58(smc_chip_t *chip, chipio_t *info);
+static int  ircc_probe_69(smc_chip_t *chip, chipio_t *info);
+static int  ircc_dma_receive(struct ircc_cb *self, int iobase); 
+static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase);
 static int  ircc_hard_xmit(struct sk_buff *skb, struct net_device *dev);
-static void ircc_dma_xmit(struct ircc_cb *self, int iobase);
+static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs);
 static void ircc_change_speed(void *priv, __u32 speed);
 static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int  ircc_is_receiving(struct ircc_cb *self);
 
 static int  ircc_net_open(struct net_device *dev);
 static int  ircc_net_close(struct net_device *dev);
+#ifdef CONFIG_APM
+static int  ircc_apmproc(apm_event_t event);
+#endif /* CONFIG_APM */
+
+/* These are the currently known SMC chipsets */
+static smc_chip_t chips[] =
+{
+	{ "FDC37C669", 0x55, 0x55, 0x0d, 0x04, ircc_probe_69 },
+	{ "FDC37N869", 0x55, 0x00, 0x0d, 0x29, ircc_probe_69 },
+	{ "FDC37N958", 0x55, 0x55, 0x20, 0x09, ircc_probe_58 },
+	{ NULL }
+};
 
 static int ircc_irq=255;
 static int ircc_dma=255;
@@ -102,26 +121,38 @@
  */
 int __init ircc_init(void)
 {
-	int ioaddr, ioaddr2;
+	static int smcreg[] = { 0x3f0, 0x370 };
+	smc_chip_t *chip;
+	chipio_t info;
+	int ret = -ENODEV;
 	int i;
 
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
-	for (i=0; (io[i] < 2000) && (i < 4); i++) {
-		int ioaddr = io[i];
-		if (check_region(ioaddr, CHIP_IO_EXTENT))
-			continue;
-		if (ircc_open(i, io[i], io2[i]) == 0)
-			return 0;
-	}
-
-	/* last chance saloon, see what the controller says */
-	if (ircc_probe_smc(&ioaddr, &ioaddr2) == 0) {
-                  if (check_region(ioaddr, CHIP_IO_EXTENT) == 0)
-                          if (ircc_open(0, ioaddr, ioaddr2) == 0)
-                                  return 0; 
-	}
 
-	return -ENODEV;
+	/* Probe for all the NSC chipsets we know about */
+	for (chip=chips; chip->name ; chip++,i++) {
+		for (i=0; i<2; i++) {
+			info.cfg_base = smcreg[i];
+			
+			/* 
+			 * First we check if the user has supplied any
+                         * parameters which we should use instead of probed
+			 * values
+			 */
+			if (io[i] < 2000) {
+				info.fir_base = io[i];
+				info.sir_base = io2[i];
+			} else if (chip->probe(chip, &info) < 0)
+				continue;
+			if (check_region(info.fir_base, CHIP_IO_EXTENT) < 0)
+				continue;
+			if (check_region(info.sir_base, CHIP_IO_EXTENT) < 0)
+				continue;
+			if (ircc_open(i, info.fir_base, info.sir_base) == 0)
+				ret = 0; 
+		}
+	}
+	return ret;
 }
 
 /*
@@ -137,7 +168,7 @@
 
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	for (i=0; i < 4; i++) {
+	for (i=0; i < 2; i++) {
 		if (dev_self[i])
 			ircc_close(dev_self[i]);
 	}
@@ -150,7 +181,7 @@
  *    Open driver instance
  *
  */
-static int ircc_open(int i, unsigned int iobase, unsigned int iobase2)
+static int ircc_open(int i, unsigned int fir_base, unsigned int sir_base)
 {
 	struct ircc_cb *self;
         struct irport_cb *irport;
@@ -159,9 +190,9 @@
 
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
-	if ((config = ircc_probe(iobase, iobase2)) == -1) {
+	if ((config = ircc_probe(fir_base, sir_base)) == -1) {
 	        IRDA_DEBUG(0, __FUNCTION__ 
-			   "(), addr 0x%04x - no device found!\n", iobase);
+			   "(), addr 0x%04x - no device found!\n", fir_base);
 		return -1;
 	}
 	
@@ -180,7 +211,7 @@
 	/* Need to store self somewhere */
 	dev_self[i] = self;
 
-	irport = irport_open(0, iobase2, config >> 4 & 0x0f);
+	irport = irport_open(i, sir_base, config >> 4 & 0x0f);
 	if (!irport)
 		return -ENODEV;
 
@@ -190,34 +221,32 @@
 	irport->priv = self;
 
 	/* Initialize IO */
-	self->io.iobase    = iobase;
-        self->io.iobase2   = iobase2; /* Used by irport */
+	self->io.fir_base  = fir_base;
+        self->io.sir_base  = sir_base; /* Used by irport */
         self->io.irq       = config >> 4 & 0x0f;
 	if (ircc_irq < 255) {
 	        MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
 			driver_name, self->io.irq, ircc_irq);
 		self->io.irq = ircc_irq;
 	}
-        self->io.io_ext    = CHIP_IO_EXTENT;
-        self->io.io_ext2   = 8;       /* Used by irport */
+        self->io.fir_ext   = CHIP_IO_EXTENT;
+        self->io.sir_ext   = 8;       /* Used by irport */
         self->io.dma       = config & 0x0f;
 	if (ircc_dma < 255) {
 	        MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
 			driver_name, self->io.dma, ircc_dma);
 		self->io.dma = ircc_dma;
 	}
-        self->io.fifo_size = 16;
 
 	/* Lock the port that we need */
-	ret = check_region(self->io.iobase, self->io.io_ext);
+	ret = check_region(self->io.fir_base, self->io.fir_ext);
 	if (ret < 0) { 
-		IRDA_DEBUG(0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
-			   self->io.iobase);
-		/* ircc_cleanup(self->self);  */
+		IRDA_DEBUG(0, __FUNCTION__ ": can't get fir_base of 0x%03x\n",
+			   self->io.fir_base);
+                kfree(self);
 		return -ENODEV;
 	}
-
-	request_region(self->io.iobase, self->io.io_ext, driver_name);
+	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&irport->qos);
@@ -229,7 +258,7 @@
 	irport->qos.min_turn_time.bits = 0x07;
 	irda_qos_bits_to_value(&irport->qos);
 
-	irport->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO;
+	irport->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
 	
 	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
 	self->rx_buff.truesize = 4000; 
@@ -256,6 +285,7 @@
 	
 	/* Override the speed change function, since we must control it now */
 	irport->change_speed = &ircc_change_speed;
+	irport->interrupt    = &ircc_interrupt;
 	self->netdev->open   = &ircc_net_open;
 	self->netdev->stop   = &ircc_net_close;
 
@@ -279,23 +309,26 @@
 
 	ASSERT(self != NULL, return -1;);
 
-        iobase = self->io.iobase;
+        iobase = self->io.fir_base;
 
 	irport_close(self->irport);
 
+	/* Stop interrupts */
 	register_bank(iobase, 0);
 	outb(0, iobase+IRCC_IER);
 	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-
+	outb(0x00, iobase+IRCC_MASTER);
+#if 0
+	/* Reset to SIR mode */
 	register_bank(iobase, 1);
-
         outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
         outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
- 
+#endif
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", self->io.iobase);
+	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", 
+		   self->io.fir_base);
 
-	release_region(self->io.iobase, self->io.io_ext);
+	release_region(self->io.fir_base, self->io.fir_ext);
 
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
@@ -310,58 +343,106 @@
 #endif /* MODULE */
 
 /*
- * Function ircc_probe_smc (ioaddr, ioaddr2)
+ * Function ircc_probe_69 (chip, info)
  *
- *    Probe the SMC Chip for an IrDA port
+ *    Probes for the SMC FDC37C669 and FDC37N869
  *
  */
-static int ircc_probe_smc(int *ioaddr, int *ioaddr2)
+static int ircc_probe_69(smc_chip_t *chip, chipio_t *info)
 {
-        static int smcreg[] = { 0x3f0, 0x370 };
+	int cfg_base = info->cfg_base;
 	__u8 devid, mode;
-	__u8 conf_reg;
-	int ret = -1;
+	int ret = -ENODEV;
 	int fir_io;
-        int i;
 	
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
-        for (i = 0; i < 2 && ret == -1; i++) {
-		conf_reg = smcreg[i];
-        
-		/* Enter configuration */
-                outb(0x55, conf_reg);
-                outb(0x55, conf_reg);
-    
-		outb(0x0d, conf_reg);
-		devid = inb(conf_reg+1);
-		IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
+	/* Enter configuration */
+	outb(chip->entr1, cfg_base);
+	outb(chip->entr2, cfg_base);
+	
+	outb(chip->cid_index, cfg_base);
+	devid = inb(cfg_base+1);
+	IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
+	
+	/* Check for expected device ID; are there others? */
+	if (devid == chip->cid_value) {
+		outb(0x0c, cfg_base);
+		mode = inb(cfg_base+1);
+		mode = (mode & 0x38) >> 3;
 		
-		/* Check for expected device ID; are there others? */
-		if (devid == 0x29) {    
-			outb(0x0c, conf_reg);
-			mode = inb(conf_reg+1);
-			mode = (mode & 0x38) >> 3;
-
-			/* Value for IR port */
-			if (mode && mode < 4) {
-				/* SIR iobase */
-				outb(0x25, conf_reg);
-				*ioaddr2 = inb(conf_reg+1) << 2;
-
-				/* FIR iobase */
-				outb(0x2b, conf_reg);
-				fir_io = inb(conf_reg+1) << 3;
-				if (fir_io) {
-					ret = 0;
-					*ioaddr = fir_io;
-				}
+		/* Value for IR port */
+		if (mode && mode < 4) {
+			/* SIR iobase */
+			outb(0x25, cfg_base);
+			info->sir_base = inb(cfg_base+1) << 2;
+
+		       	/* FIR iobase */
+			outb(0x2b, cfg_base);
+			fir_io = inb(cfg_base+1) << 3;
+			if (fir_io) {
+				ret = 0;
+				info->fir_base = fir_io;
 			}
 		}
+	}
+	
+	/* Exit configuration */
+	outb(0xaa, cfg_base);
+
+	return ret;
+}
+
+/*
+ * Function ircc_probe_58 (chip, info)
+ *
+ *    Probes for the SMC FDC37N958
+ *
+ */
+static int ircc_probe_58(smc_chip_t *chip, chipio_t *info)
+{
+	int cfg_base = info->cfg_base;
+	__u8 devid;
+	int ret = -ENODEV;
+	int fir_io;
+	
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	/* Enter configuration */
+	outb(chip->entr1, cfg_base);
+	outb(chip->entr2, cfg_base);
+	
+	outb(chip->cid_index, cfg_base);
+	devid = inb(cfg_base+1);
+	IRDA_DEBUG(0, __FUNCTION__ "(), devid=0x%02x\n",devid);
+	
+	/* Check for expected device ID; are there others? */
+	if (devid == chip->cid_value) {
+		/* Select logical device (UART2) */
+		outb(0x07, cfg_base);
+		outb(0x05, cfg_base + 1);
+		
+		/* SIR iobase */
+		outb(0x60, cfg_base);
+		info->sir_base = inb(cfg_base + 1) << 8;
+		outb(0x61, cfg_base);
+		info->sir_base |= inb(cfg_base + 1);
+		
+		/* Read FIR base */
+		outb(0x62, cfg_base);
+		fir_io = inb(cfg_base + 1) << 8;
+		outb(0x63, cfg_base);
+		fir_io |= inb(cfg_base + 1);
+		outb(0x2b, cfg_base);
+		if (fir_io) {
+			ret = 0;
+			info->fir_base = fir_io;
+		}
+	}
+	
+	/* Exit configuration */
+	outb(0xaa, cfg_base);
 
-		/* Exit configuration */
-		outb(0xaa, conf_reg);
-        }
 	return ret;
 }
 
@@ -371,34 +452,32 @@
  *    Returns non-negative on success.
  *
  */
-static int ircc_probe(int iobase, int iobase2) 
+static int ircc_probe(int fir_base, int sir_base) 
 {
-	int version = 1;
 	int low, high, chip, config, dma, irq;
-	
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	int iobase = fir_base;
+	int version = 1;
 
-	/* Power on device */
-	outb(inb(iobase+IRCC_MASTER) & ~IRCC_MASTER_POWERDOWN, 
-	     iobase+IRCC_MASTER);
+	IRDA_DEBUG(0, __FUNCTION__ "\n");
 
 	register_bank(iobase, 3);
-	high = inb(iobase+IRCC_ID_HIGH);
-	low = inb(iobase+IRCC_ID_LOW);
-	chip = inb(iobase+IRCC_CHIP_ID);
+	high    = inb(iobase+IRCC_ID_HIGH);
+	low     = inb(iobase+IRCC_ID_LOW);
+	chip    = inb(iobase+IRCC_CHIP_ID);
 	version = inb(iobase+IRCC_VERSION);
-	config = inb(iobase+IRCC_INTERFACE);
-	irq = config >> 4 & 0x0f;
-	dma = config & 0x0f;
+	config  = inb(iobase+IRCC_INTERFACE);
+	irq     = config >> 4 & 0x0f;
+	dma     = config & 0x0f;
 
         if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2)) { 
-                IRDA_DEBUG(0, "SMC IrDA Controller found; IrCC version %d.%d, "
-		      "port 0x%04x, dma %d, interrupt %d\n",
-                      chip & 0x0f, version, iobase, dma, irq);
+                MESSAGE("SMC IrDA Controller found; IrCC version %d.%d, "
+			"port 0x%03x, dma=%d, irq=%d\n",
+			chip & 0x0f, version, iobase, dma, irq);
 	} else
-		return -1;
+		return -ENODEV;
 
-	outb(0, iobase+IRCC_MASTER);
+	/* Power on device */
+	outb(0x00, iobase+IRCC_MASTER);
 
 	return config;
 }
@@ -411,7 +490,7 @@
  */
 static void ircc_change_speed(void *priv, __u32 speed)
 {
-	int iobase, ir_mode, select, fast; 
+	int iobase, ir_mode, ctrl, fast; 
 	struct ircc_cb *self = (struct ircc_cb *) priv;
 	struct net_device *dev;
 
@@ -420,49 +499,39 @@
 	ASSERT(self != NULL, return;);
 
 	dev = self->netdev;
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Update accounting for new speed */
 	self->io.speed = speed;
 
+	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
+	outb(0x00, iobase+IRCC_MASTER);
+
 	switch (speed) {
 	case 9600:
 	case 19200:
 	case 38400:
 	case 57600:
-	case 115200:
-	        IRDA_DEBUG(0, __FUNCTION__ 
-			   "(), using irport to change speed to %d\n", speed);
-
-		register_bank(iobase, 0);
-		outb(0, iobase+IRCC_IER);
-		outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-		outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
-
-		dev->hard_start_xmit = &irport_hard_xmit;
-
-		/* We must give the interrupt back to irport */
-		self->irport->interrupt = irport_interrupt;
-
-		irport_start(self->irport);
-		irport_change_speed(self->irport, speed);
-		return;
+	case 115200:		
+		ir_mode = IRCC_CFGA_IRDA_SIR_A;
+		ctrl = 0;
+		fast = 0;
 		break;
 	case 576000:		
 		ir_mode = IRCC_CFGA_IRDA_HDLC;
-		select = 0;
+		ctrl = IRCC_CRC;
 		fast = 0;
 		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
 		break;
 	case 1152000:
 		ir_mode = IRCC_CFGA_IRDA_HDLC;
-		select = IRCC_1152;
+		ctrl = IRCC_1152 | IRCC_CRC;
 		fast = 0;
 		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
 		break;
 	case 4000000:
 		ir_mode = IRCC_CFGA_IRDA_4PPM;
-		select = 0;
+		ctrl = IRCC_CRC;
 		fast = IRCC_LCR_A_FAST;
 		IRDA_DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
 		break;
@@ -471,39 +540,55 @@
 			   speed);
 		return;
 	}
-
-	outb(IRCC_MASTER_RESET, iobase+IRCC_MASTER);
-
+	
 	register_bank(iobase, 0);
 	outb(0, iobase+IRCC_IER);
-	
-       	irport_stop(self->irport);	
-
-	/* Install FIR transmit handler */
-	dev->hard_start_xmit = &ircc_hard_xmit;
+	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
 
-	/* Need to steal the interrupt as well */
-	self->irport->interrupt = &ircc_interrupt;
+	/* Make special FIR init if necessary */
+	if (speed > 115200) {
+		irport_stop(self->irport);
+
+		/* Install FIR transmit handler */
+		dev->hard_start_xmit = &ircc_hard_xmit;
+
+		/* 
+		 * Don't know why we have to do this, but FIR interrupts 
+		 * stops working if we remove it.
+		 */
+		/* outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR); */
 
+		/* Be ready for incomming frames */
+		ircc_dma_receive(self, iobase);
+	} else {
+		/* Install SIR transmit handler */
+		dev->hard_start_xmit = &irport_hard_xmit;
+		irport_start(self->irport);
+		
+	        IRDA_DEBUG(0, __FUNCTION__ 
+			   "(), using irport to change speed to %d\n", speed);
+		irport_change_speed(self->irport, speed);
+	}	
 	dev->tbusy = 0;
-	
+
 	register_bank(iobase, 1);
 	outb(((inb(iobase+IRCC_SCE_CFGA) & 0x87) | ir_mode), 
 	     iobase+IRCC_SCE_CFGA);
-	
-	outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_IR), 
-	     iobase+IRCC_SCE_CFGB);
 
+#ifdef SMC_669 /* Uses pin 88/89 for Rx/Tx */
+	outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_COM), 
+	     iobase+IRCC_SCE_CFGB);
+#else	
+	outb(((inb(iobase+IRCC_SCE_CFGB) & 0x3f) | IRCC_CFGB_MUX_IR),
+	     iobase+IRCC_SCE_CFGB);
+#endif	
 	(void) inb(iobase+IRCC_FIFO_THRESHOLD);
 	outb(64, iobase+IRCC_FIFO_THRESHOLD);
-
+	
 	register_bank(iobase, 4);
-
-	outb((inb(iobase+IRCC_CONTROL) & 0x30) | select | IRCC_CRC, 
-	     iobase+IRCC_CONTROL);
-
+	outb((inb(iobase+IRCC_CONTROL) & 0x30) | ctrl, iobase+IRCC_CONTROL);
+	
 	register_bank(iobase, 0);
-
 	outb(fast, iobase+IRCC_LCR_A);
 }
 
@@ -517,21 +602,20 @@
 {
 	struct irport_cb *irport;
 	struct ircc_cb *self;
+	unsigned long flags;
+	__u32 speed;
 	int iobase;
 	int mtt;
-	__u32 speed;
 
 	irport = (struct irport_cb *) dev->priv;
 	self = (struct ircc_cb *) irport->priv;
-
 	ASSERT(self != NULL, return 0;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies,
-		   (int) skb->len);
+	spin_lock_irqsave(&self->lock, flags);
 
-	/* Check if we need to change the speed */
+	/* Check if we need to change the speed after this frame */
 	if ((speed = irda_get_speed(skb)) != self->io.speed)
 		self->new_speed = speed;
 	
@@ -541,19 +625,28 @@
 
 	memcpy(self->tx_buff.head, skb->data, skb->len);
 
-	/* Make sure that the length is a multiple of 16 bits */
-	if (skb->len & 0x01)
-		skb->len++;
-
 	self->tx_buff.len = skb->len;
 	self->tx_buff.data = self->tx_buff.head;
 	
 	mtt = irda_get_mtt(skb);	
-	if (mtt)
-		udelay(mtt);
-	
-	ircc_dma_xmit(self, iobase);
+	if (mtt) {
+		int bofs;
+
+		/* 
+		 * Compute who many BOFS (STA or PA's) we need to waste the
+		 * min turn time given the speed of the link.
+		 */
+		bofs = mtt * (self->io.speed / 1000) / 8000;
+		if (bofs > 4095)
+			bofs = 4095;
+
+		ircc_dma_xmit(self, iobase, bofs);
+	} else {
+		/* Transmit frame */
+		ircc_dma_xmit(self, iobase, 0);
+	}
 	
+	spin_unlock_irqrestore(&self->lock, flags);
 	dev_kfree_skb(skb);
 
 	return 0;
@@ -565,44 +658,49 @@
  *    Transmit data using DMA
  *
  */
-static void ircc_dma_xmit(struct ircc_cb *self, int iobase)
+static void ircc_dma_xmit(struct ircc_cb *self, int iobase, int bofs)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "\n");
-
-	ASSERT(self != NULL, return;);
+	__u8 ctrl;
 
-	iobase = self->io.iobase;
+	IRDA_DEBUG(2, __FUNCTION__ "\n");
+#if 0	
+	/* Disable Rx */
+	register_bank(iobase, 0);
+	outb(0x00, iobase+IRCC_LCR_B);
+#endif
+	register_bank(iobase, 1);
+	outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
+	     iobase+IRCC_SCE_CFGB);
 
-	setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, 
-		  DMA_TX_MODE);
-	
 	self->io.direction = IO_XMIT;
 
-	outb(0x08, self->io.iobase2+4);
-	
+	/* Set BOF additional count for generating the min turn time */
 	register_bank(iobase, 4);
-	outb((inb(iobase+IRCC_CONTROL) & 0xf0), iobase+IRCC_CONTROL);
-	
-	outb(2, iobase+IRCC_BOF_COUNT_LO);
-	outb(0, iobase+IRCC_BRICKWALL_CNT_LO);
-#if 1
-	outb(self->tx_buff.len >> 8, iobase+IRCC_BRICKWALL_TX_CNT_HI);
+	outb(bofs & 0xff, iobase+IRCC_BOF_COUNT_LO);
+	ctrl = inb(iobase+IRCC_CONTROL) & 0xf0;
+	outb(ctrl | ((bofs >> 8) & 0x0f), iobase+IRCC_BOF_COUNT_HI);
+
+	/* Set max Tx frame size */
+	outb(self->tx_buff.len >> 8, iobase+IRCC_TX_SIZE_HI);
 	outb(self->tx_buff.len & 0xff, iobase+IRCC_TX_SIZE_LO);
-#else
-	outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI);
-	outb(0, iobase+IRCC_TX_SIZE_LO);
-#endif
 
+	/* Setup DMA controller (must be done after enabling chip DMA) */
+	setup_dma(self->io.dma, self->tx_buff.data, self->tx_buff.len, 
+		  DMA_TX_MODE);
+
+	outb(UART_MCR_OUT2, self->io.sir_base + UART_MCR);
+	/* Enable burst mode chip Tx DMA */
 	register_bank(iobase, 1);
-	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE,
-	     iobase+IRCC_SCE_CFGB);
+	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE |
+	     IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
 
+	/* Enable interrupt */
+	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
 	register_bank(iobase, 0);
-
 	outb(IRCC_IER_ACTIVE_FRAME | IRCC_IER_EOM, iobase+IRCC_IER);
-	outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
 
-	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
+	/* Enable transmit */
+	outb(IRCC_LCR_B_SCE_TRANSMIT|IRCC_LCR_B_SIP_ENABLE, iobase+IRCC_LCR_B);
 }
 
 /*
@@ -612,39 +710,36 @@
  *    by the interrupt handler
  *
  */
-static void ircc_dma_xmit_complete(struct ircc_cb *self, int underrun)
+static void ircc_dma_xmit_complete(struct ircc_cb *self, int iobase)
 {
-	int iobase, d;
-
 	IRDA_DEBUG(2, __FUNCTION__ "\n");
-
-	ASSERT(self != NULL, return;);
-
-	register_bank(self->io.iobase, 1);
-
-	outb(inb(self->io.iobase+IRCC_SCE_CFGB) & IRCC_CFGB_DMA_ENABLE,
-	     self->io.iobase+IRCC_SCE_CFGB);
-
-	d = get_dma_residue(self->io.dma);
-
-	IRDA_DEBUG(0, __FUNCTION__ 
-		   ": dma residue = %d, len=%d, sent=%d\n", 
-		   d, self->tx_buff.len, self->tx_buff.len - d);
-
-	iobase = self->io.iobase;
+#if 0
+	/* Disable Tx */
+	register_bank(iobase, 0);
+	outb(0x00, iobase+IRCC_LCR_B);
+#endif
+	register_bank(self->io.fir_base, 1);
+	outb(inb(self->io.fir_base+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE,
+	     self->io.fir_base+IRCC_SCE_CFGB);
 
 	/* Check for underrrun! */
-	if (underrun) {
+	register_bank(iobase, 0);
+	if (inb(iobase+IRCC_LSR) & IRCC_LSR_UNDERRUN) {
 		self->irport->stats.tx_errors++;
-		self->irport->stats.tx_fifo_errors++;		
+		self->irport->stats.tx_fifo_errors++;
+
+		/* Reset error condition */
+		register_bank(iobase, 0);
+		outb(IRCC_MASTER_ERROR_RESET, iobase+IRCC_MASTER);
+		outb(0x00, iobase+IRCC_MASTER);
 	} else {
 		self->irport->stats.tx_packets++;
 		self->irport->stats.tx_bytes +=  self->tx_buff.len;
 	}
 
+	/* Check if it's time to change the speed */
 	if (self->new_speed) {
-		ircc_change_speed(self, self->new_speed);
-		
+		ircc_change_speed(self, self->new_speed);		
 		self->new_speed = 0;
 	}
 
@@ -662,39 +757,31 @@
  *    if it starts to receive a frame.
  *
  */
-static int ircc_dma_receive(struct ircc_cb *self) 
-{
-	int iobase;
-
-	IRDA_DEBUG(2, __FUNCTION__ "\n");
-
-	ASSERT(self != NULL, return -1;);
-
-	iobase= self->io.iobase;
+static int ircc_dma_receive(struct ircc_cb *self, int iobase) 
+{	
+	/* Turn off chip DMA */
+	//register_bank(iobase, 1);
+	//outb(inb(iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
+	//     iobase+IRCC_SCE_CFGB);
 
 	setup_dma(self->io.dma, self->rx_buff.data, self->rx_buff.truesize, 
-		   DMA_RX_MODE);
-	
-	/* driver->media_busy = FALSE; */
+		  DMA_RX_MODE);
+	/* Set max Rx frame size */
+	register_bank(iobase, 4);
+	outb((2050 >> 8) & 0x0f, iobase+IRCC_RX_SIZE_HI);
+	outb(2050 & 0xff, iobase+IRCC_RX_SIZE_LO);
+
 	self->io.direction = IO_RECV;
 	self->rx_buff.data = self->rx_buff.head;
-#if 0
-	self->rx_buff.offset = 0;
-#endif
-
-	register_bank(iobase, 4);
-	outb(inb(iobase+IRCC_CONTROL) & 0xf0, iobase+IRCC_CONTROL);
-	outb(2, iobase+IRCC_BOF_COUNT_LO);
-	outb(0, iobase+IRCC_BRICKWALL_CNT_LO);
-	outb(0, iobase+IRCC_BRICKWALL_TX_CNT_HI);
-	outb(0, iobase+IRCC_TX_SIZE_LO);
-	outb(0, iobase+IRCC_RX_SIZE_HI);
-	outb(0, iobase+IRCC_RX_SIZE_LO);
 
+	/* Setup DMA controller */
+	
+	/* Enable receiver */
 	register_bank(iobase, 0);
 	outb(IRCC_LCR_B_SCE_RECEIVE | IRCC_LCR_B_SIP_ENABLE, 
 	     iobase+IRCC_LCR_B);
 	
+	/* Enable burst mode chip Rx DMA */
 	register_bank(iobase, 1);
 	outb(inb(iobase+IRCC_SCE_CFGB) | IRCC_CFGB_DMA_ENABLE | 
 	     IRCC_CFGB_DMA_BURST, iobase+IRCC_SCE_CFGB);
@@ -709,45 +796,54 @@
  *
  *    
  */
-static int ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
+static void ircc_dma_receive_complete(struct ircc_cb *self, int iobase)
 {
+	unsigned long flags;
 	struct sk_buff *skb;
 	int len, msgcnt;
 
 	IRDA_DEBUG(2, __FUNCTION__ "\n");
+#if 0
+	/* Disable Rx */
+	register_bank(iobase, 0);
+	outb(0x00, iobase+IRCC_LCR_B);
+#endif
+	register_bank(iobase, 0);
+	msgcnt = inb(iobase+IRCC_LCR_B) & 0x08;
 
-	msgcnt = inb(self->io.iobase+IRCC_LCR_B) & 0x08;
-
-	IRDA_DEBUG(0, __FUNCTION__ ": dma count = %d\n",
+	IRDA_DEBUG(2, __FUNCTION__ ": dma count = %d\n",
 		   get_dma_residue(self->io.dma));
 
-	len = self->rx_buff.truesize - get_dma_residue(self->io.dma) - 4;
+	len = self->rx_buff.truesize - get_dma_residue(self->io.dma);
+	
+	/* Remove CRC */
+	if (self->io.speed < 4000000)
+		len -= 2;
+	else
+		len -= 4;
 
-	IRDA_DEBUG(0, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
+	if ((len < 2) && (len > 2050)) {
+		WARNING(__FUNCTION__ "(), bogus len=%d\n", len);
+		return;
+	}
+	IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
 
 	skb = dev_alloc_skb(len+1);
 	if (!skb)  {
 		WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n");
-		return FALSE;
-	}
-			
+		return;
+	}			
 	/* Make sure IP header gets aligned */
 	skb_reserve(skb, 1); 
-	skb_put(skb, len);
 
-	memcpy(skb->data, self->rx_buff.data, len);
+	memcpy(skb_put(skb, len), self->rx_buff.data, len);
 	self->irport->stats.rx_packets++;
+	self->irport->stats.rx_bytes += len;
 
 	skb->dev = self->netdev;
 	skb->mac.raw  = skb->data;
 	skb->protocol = htons(ETH_P_IRDA);
 	netif_rx(skb);
-
-	register_bank(self->io.iobase, 1);
-	outb(inb(self->io.iobase+IRCC_SCE_CFGB) & ~IRCC_CFGB_DMA_ENABLE, 
-	     self->io.iobase+IRCC_SCE_CFGB);
-
-	return TRUE;
 }
 
 /*
@@ -758,58 +854,54 @@
  */
 static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int iobase, iir;
 	struct net_device *dev = (struct net_device *) dev_id;
+	struct irport_cb *irport;
 	struct ircc_cb *self;
+	int iobase, iir;
 
 	if (dev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", 
 		       driver_name, irq);
 		return;
 	}
-	
-	self = (struct ircc_cb *) dev->priv;
+	irport = (struct irport_cb *) dev->priv;
+	ASSERT(irport != NULL, return;);
+	self = (struct ircc_cb *) irport->priv;
+	ASSERT(self != NULL, return;);
 
-	iobase = self->io.iobase;
+	/* Check if we should use the SIR interrupt handler */
+	if (self->io.speed < 576000) {
+		irport_interrupt(irq, dev_id, regs);
+		return;
+	}
+	iobase = self->io.fir_base;
 
+	spin_lock(&self->lock);	
 	dev->interrupt = 1;
 
-	outb(0, iobase+IRCC_MASTER);
-
 	register_bank(iobase, 0);
 	iir = inb(iobase+IRCC_IIR);
 
 	/* Disable interrupts */
 	outb(0, iobase+IRCC_IER);
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), iir = 0x%02x\n", iir);
+	IRDA_DEBUG(2, __FUNCTION__ "(), iir = 0x%02x\n", iir);
 
 	if (iir & IRCC_IIR_EOM) {
-	        IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_EOM\n");
-
 		if (self->io.direction == IO_RECV)
 			ircc_dma_receive_complete(self, iobase);
 		else
 			ircc_dma_xmit_complete(self, iobase);
 		
-		ircc_dma_receive(self);
-	}
-	if (iir & IRCC_IIR_ACTIVE_FRAME) {
-	        IRDA_DEBUG(0, __FUNCTION__ "(), IRCC_IIR_ACTIVE_FRAME\n");
-		self->rx_buff.state = INSIDE_FRAME;
-#if 0
-		ircc_dma_receive(self);
-#endif
-	}
-	if (iir & IRCC_IIR_RAW_MODE) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), IIR RAW mode interrupt.\n");
+		ircc_dma_receive(self, iobase);
 	}
 
+	/* Enable interrupts again */
 	register_bank(iobase, 0);
 	outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
-	outb(IRCC_MASTER_INT_EN, iobase+IRCC_MASTER);
 
 	dev->interrupt = 0;
+	spin_unlock(&self->lock);
 }
 
 /*
@@ -855,7 +947,7 @@
 
 	ASSERT(self != NULL, return 0;);
 	
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	irport_net_open(dev); /* irport allocates the irq */
 
@@ -894,7 +986,7 @@
 	
 	ASSERT(self != NULL, return 0;);
 	
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	irport_net_close(dev);
 
@@ -906,6 +998,69 @@
 
 	return 0;
 }
+
+#ifdef CONFIG_APM
+static void ircc_suspend(struct ircc_cb *self)
+{
+	int i = 10;
+
+	MESSAGE("%s, Suspending\n", driver_name);
+
+	if (self->io.suspended)
+		return;
+
+	ircc_net_close(self->netdev);
+
+	self->io.suspended = 1;
+}
+
+static void ircc_wakeup(struct ircc_cb *self)
+{
+	struct net_device *dev = self->netdev;
+	unsigned long flags;
+
+	if (!self->io.suspended)
+		return;
+
+	save_flags(flags);
+	cli();
+
+	ircc_net_open(self->netdev);
+	
+	restore_flags(flags);
+	MESSAGE("%s, Waking up\n", driver_name);
+}
+
+static int ircc_apmproc(apm_event_t event)
+{
+	static int down = 0;          /* Filter out double events */
+	int i;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (!down) {			
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					ircc_suspend(dev_self[i]);
+			}
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (down) {
+			for (i=0; i<4; i++) {
+				if (dev_self[i])
+					ircc_wakeup(dev_self[i]);
+			}
+		}
+		down = 0;
+		break;
+	}
+	return 0;
+}
+#endif /* CONFIG_APM */
 
 #ifdef MODULE
 MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.3.41/linux/drivers/net/irda/toshoboe.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/toshoboe.c	Fri Jan 28 19:36:22 2000
@@ -32,37 +32,6 @@
 
 static char *rcsid = "$Id: toshoboe.c,v 1.91 1999/06/29 14:21:06 root Exp $";
 
-/* 
- * $Log: toshoboe.c,v $
- * Revision 1.9  1999/06/29 14:21:06  root
- * *** empty log message ***
- *
- * Revision 1.8  1999/06/29 14:15:08  root
- * *** empty log message ***
- *
- * Revision 1.7  1999/06/29 13:46:42  root
- * *** empty log message ***
- *
- * Revision 1.6  1999/06/29 12:31:03  root
- * *** empty log message ***
- *
- * Revision 1.5  1999/05/12 12:24:39  root
- * *** empty log message ***
- *
- * Revision 1.4  1999/05/12 11:55:08  root
- * *** empty log message ***
- *
- * Revision 1.3  1999/05/09 01:33:12  root
- * *** empty log message ***
- *
- * Revision 1.2  1999/05/09 01:30:38  root
- * *** empty log message ***
- *
- * Revision 1.1  1999/05/09 01:25:04  root
- * Initial revision
- * 
- */
-
 /* Define this to have only one frame in the XMIT or RECV queue */
 /* Toshiba's drivers do this, but it disables back to back tansfers */
 /* I think that the chip may have some problems certainly, I have */
@@ -682,7 +651,7 @@
       toshoboe_disablebm (self);
     }
 
-  release_region (self->io.iobase, self->io.io_ext);
+  release_region (self->io.sir_base, self->io.sir_ext);
 
 
   for (i = 0; i < TX_SLOTS; ++i)
@@ -754,17 +723,17 @@
   self->pdev = pci_dev;
   self->base = pci_dev->resource[0].start;
 
-  self->io.iobase = self->base;
+  self->io.sir_base = self->base;
   self->io.irq = pci_dev->irq;
-  self->io.io_ext = CHIP_IO_EXTENT;
+  self->io.sir_ext = CHIP_IO_EXTENT;
   self->io.speed = 9600;
 
   /* Lock the port that we need */
-  i = check_region (self->io.iobase, self->io.io_ext);
+  i = check_region (self->io.sir_base, self->io.sir_ext);
   if (i < 0)
     {
       IRDA_DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-             self->io.iobase);
+             self->io.sir_base);
 
       dev_self[i] = NULL;
       kfree (self);
@@ -864,13 +833,12 @@
 
     }
 
-  request_region (self->io.iobase, self->io.io_ext, driver_name);
+  request_region (self->io.sir_base, self->io.sir_ext, driver_name);
 
   if (!(dev = dev_alloc("irda%d", &err))) {
 	  ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
 	  return -ENOMEM;
   }
-
   dev->priv = (void *) self;
   self->netdev = dev;
   
@@ -1025,7 +993,7 @@
       if (pci_dev)
         {
           printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
-                  pci_dev->resource[0].start,
+		  pci_dev->resource[0].start,
                   pci_dev->irq);
 
           if (!toshoboe_open (pci_dev))
diff -u --recursive --new-file v2.3.41/linux/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- v2.3.41/linux/drivers/net/irda/w83977af_ir.c	Fri Jan  7 19:13:22 2000
+++ linux/drivers/net/irda/w83977af_ir.c	Fri Jan 28 19:36:22 2000
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Wed Jan  5 15:11:21 2000
+ * Modified at:   Fri Jan 28 12:10:59 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
@@ -183,21 +183,21 @@
 	dev_self[i] = self;
 
 	/* Initialize IO */
-	self->io.iobase    = iobase;
+	self->io.fir_base   = iobase;
         self->io.irq       = irq;
-        self->io.io_ext    = CHIP_IO_EXTENT;
+        self->io.fir_ext   = CHIP_IO_EXTENT;
         self->io.dma       = dma;
         self->io.fifo_size = 32;
 
 	/* Lock the port that we need */
-	ret = check_region(self->io.iobase, self->io.io_ext);
+	ret = check_region(self->io.fir_base, self->io.fir_ext);
 	if (ret < 0) { 
 		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-		      self->io.iobase);
+		      self->io.fir_base);
 		/* w83977af_cleanup( self);  */
 		return -ENODEV;
 	}
-	request_region(self->io.iobase, self->io.io_ext, driver_name);
+	request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&self->qos);
@@ -243,9 +243,6 @@
 		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
 		return -ENOMEM;
 	}
-	/* dev_alloc doesn't clear the struct, so lets do a little hack */
-	memset(((__u8*)dev)+sizeof(char*),0,sizeof(struct net_device)-sizeof(char*));
-
 	dev->priv = (void *) self;
 	self->netdev = dev;
 
@@ -282,7 +279,7 @@
 
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
-        iobase = self->io.iobase;
+        iobase = self->io.fir_base;
 
 #ifdef CONFIG_USE_W977_PNP
 	/* enter PnP configuration mode */
@@ -301,14 +298,12 @@
 		rtnl_lock();
 		unregister_netdevice(self->netdev);
 		rtnl_unlock();
-		/* Must free the old-style 2.2.x device */
-		kfree(self->netdev);
 	}
 
 	/* Release the PORT that this driver is using */
 	IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
-	      self->io.iobase);
-	release_region(self->io.iobase, self->io.io_ext);
+	      self->io.fir_base);
+	release_region(self->io.fir_base, self->io.fir_ext);
 
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
@@ -426,7 +421,7 @@
 	int iobase; 
 	__u8 set;
 
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Update accounting for new speed */
 	self->io.speed = speed;
@@ -510,7 +505,7 @@
 	
 	self = (struct w83977af_ir *) dev->priv;
 
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	IRDA_DEBUG(4, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, 
 		   (int) skb->len);
@@ -692,7 +687,7 @@
 
 	ASSERT(self != NULL, return;);
 
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Save current set */
 	set = inb(iobase+SSR);
@@ -748,7 +743,7 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "\n");
 
-	iobase= self->io.iobase;
+	iobase= self->io.fir_base;
 
 	/* Save current set */
 	set = inb(iobase+SSR);
@@ -822,12 +817,12 @@
 
 	st_fifo = &self->st_fifo;
 
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Save current set */
 	set = inb(iobase+SSR);
 	
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Read status FIFO */
 	switch_bank(iobase, SET5);
@@ -948,7 +943,7 @@
 
 	ASSERT(self != NULL, return;);
 	
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 	
 	/*  Receive all characters in Rx FIFO */
 	do {
@@ -973,11 +968,11 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);
 	
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 	/* Transmit FIFO low on data */
 	if (isr & ISR_TXTH_I) {
 		/* Write data left in transmit buffer */
-		actual = w83977af_pio_write(self->io.iobase, 
+		actual = w83977af_pio_write(self->io.fir_base, 
 					    self->tx_buff.data, 
 					    self->tx_buff.len, 
 					    self->io.fifo_size);
@@ -1042,7 +1037,7 @@
 	__u8 set;
 	int iobase;
 
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 	set = inb(iobase+SSR);
 	
 	/* End of frame detected in FIFO */
@@ -1131,7 +1126,7 @@
 
 	dev->interrupt = 1;
 
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Save current bank */
 	set = inb(iobase+SSR);
@@ -1171,7 +1166,7 @@
 	ASSERT(self != NULL, return FALSE;);
 
 	if (self->io.speed > 115200) {
-		iobase = self->io.iobase;
+		iobase = self->io.fir_base;
 
 		/* Check if rx FIFO is not empty */
 		set = inb(iobase+SSR);
@@ -1225,7 +1220,7 @@
 	
 	ASSERT(self != NULL, return 0;);
 	
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	if (request_irq(self->io.irq, w83977af_interrupt, 0, dev->name, 
 			(void *) dev)) {
@@ -1290,7 +1285,7 @@
 	
 	ASSERT(self != NULL, return 0;);
 	
-	iobase = self->io.iobase;
+	iobase = self->io.fir_base;
 
 	/* Stop device */
 	dev->tbusy = 1;
diff -u --recursive --new-file v2.3.41/linux/drivers/net/mac89x0.c linux/drivers/net/mac89x0.c
--- v2.3.41/linux/drivers/net/mac89x0.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/mac89x0.c	Mon Jan 31 10:34:12 2000
@@ -0,0 +1,678 @@
+/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
+/*
+	Written 1996 by Russell Nelson, with reference to skeleton.c
+	written 1993-1994 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	The author may be reached at nelson@crynwr.com, Crynwr
+	Software, 11 Grant St., Potsdam, NY 13676
+
+  Changelog:
+
+  Mike Cruse        : mcruse@cti-ltd.com
+                    : Changes for Linux 2.0 compatibility. 
+                    : Added dev_id parameter in net_interrupt(),
+                    : request_irq() and free_irq(). Just NULL for now.
+
+  Mike Cruse        : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
+                    : in net_open() and net_close() so kerneld would know
+                    : that the module is in use and wouldn't eject the 
+                    : driver prematurely.
+
+  Mike Cruse        : Rewrote init_module() and cleanup_module using 8390.c
+                    : as an example. Disabled autoprobing in init_module(),
+                    : not a good thing to do to other devices while Linux
+                    : is running from all accounts.
+                    
+  Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
+
+  David Huggins-Daines <dhd@debian.org>
+  
+  Split this off into mac89x0.c, and gutted it of all parts which are
+  not relevant to the existing CS8900 cards on the Macintosh
+  (i.e. basically the Daynaport CS and LC cards).  To be precise:
+
+    * Removed all the media-detection stuff, because these cards are
+    TP-only.
+
+    * Lobotomized the ISA interrupt bogosity, because these cards use
+    a hardwired NuBus interrupt and a magic ISAIRQ value in the card.
+
+    * Basically eliminated everything not relevant to getting the
+    cards minimally functioning on the Macintosh.
+
+  I might add that these cards are badly designed even from the Mac
+  standpoint, in that Dayna, in their infinite wisdom, used NuBus slot
+  I/O space and NuBus interrupts for these cards, but neglected to
+  provide anything even remotely resembling a NuBus ROM.  Therefore we
+  have to probe for them in a brain-damaged ISA-like fashion.
+*/
+
+static char *version =
+"cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
+
+/* ======================= configure the driver here ======================= */
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+
+/* ======================= end of configuration ======================= */
+
+
+/* Always include 'config.h' first in case the user wants to turn on
+   or override something. */
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#define PRINTK(x) printk x
+
+/*
+  Sources:
+
+	Crynwr packet driver epktisa.
+
+	Crystal Semiconductor data sheets.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/nubus.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/hwtest.h>
+#include <asm/macints.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include "cs89x0.h"
+
+static unsigned int net_debug = NET_DEBUG;
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct net_device_stats stats;
+	int chip_type;		/* one of: CS8900, CS8920, CS8920M */
+	char chip_revision;	/* revision letter of the chip ('A'...) */
+	int send_cmd;		/* the propercommand used to send a packet. */
+	int rx_mode;
+	int curr_rx_cfg;
+        int send_underrun;      /* keep track of how many underruns in a row we get */
+	struct sk_buff *skb;
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int mac89x0_probe(struct net_device *dev);
+extern void reset_chip(struct net_device *dev);
+static int net_open(struct net_device *dev);
+static int	net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void set_multicast_list(struct net_device *dev);
+static void net_rx(struct net_device *dev);
+static int net_close(struct net_device *dev);
+static struct net_device_stats *net_get_stats(struct net_device *dev);
+static int set_mac_address(struct net_device *dev, void *addr);
+
+
+/* Example routines you must write ;->. */
+#define tx_done(dev) 1
+
+/* For reading/writing registers ISA-style */
+static int inline
+readreg_io(struct net_device *dev, int portno)
+{
+	writew(swab16(portno), dev->base_addr + ADD_PORT);
+	return swab16(readw(dev->base_addr + DATA_PORT));
+}
+
+static void inline
+writereg_io(struct net_device *dev, int portno, int value)
+{
+	writew(swab16(portno), dev->base_addr + ADD_PORT);
+	writew(swab16(value), dev->base_addr + DATA_PORT);
+}
+
+/* These are for reading/writing registers in shared memory */
+static int inline
+readreg(struct net_device *dev, int portno)
+{
+	return swab16(readw(dev->mem_start + portno));
+}
+
+static void inline
+writereg(struct net_device *dev, int portno, int value)
+{
+	writew(swab16(value), dev->mem_start + portno);
+}
+
+/* Probe for the CS8900 card in slot E.  We won't bother looking
+   anywhere else until we have a really good reason to do so. */
+int __init mac89x0_probe(struct net_device *dev)
+{
+	static int once_is_enough = 0;
+	struct net_local *lp;
+	static unsigned version_printed = 0;
+	int i, slot;
+	unsigned rev_type = 0;
+	unsigned long ioaddr;
+	unsigned short sig;
+
+	if (once_is_enough)
+		return ENODEV;
+	once_is_enough = 1;
+
+	/* We might have to parameterize this later */
+	slot = 0xE;
+	/* Get out now if there's a real NuBus card in slot E */
+	if (nubus_find_slot(slot, NULL) != NULL)
+		return ENODEV;	
+
+	/* The pseudo-ISA bits always live at offset 0x300 (gee,
+           wonder why...) */
+	ioaddr = (unsigned long)
+		nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
+	{
+		unsigned long flags;
+		int card_present;
+		
+		save_flags(flags);
+		cli();
+		card_present = hwreg_present((void*) ioaddr+4)
+		  && hwreg_present((void*) ioaddr + DATA_PORT);
+		restore_flags(flags);
+
+		if (!card_present)
+			return ENODEV;
+	}
+
+	writew(0, ioaddr + ADD_PORT);
+	sig = readw(ioaddr + DATA_PORT);
+	if (sig != swab16(CHIP_EISA_ID_SIG))
+		return ENODEV;
+
+	/* Initialize the net_device structure. */
+	if (dev->priv == NULL) {
+		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+                memset(dev->priv, 0, sizeof(struct net_local));
+        }
+	lp = (struct net_local *)dev->priv;
+
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = ioaddr;
+	dev->mem_start = (unsigned long) 
+		nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
+	dev->mem_end = dev->mem_start + 0x1000;
+
+	/* Turn on shared memory */
+	writereg_io(dev, PP_BusCTL, MEMORY_ON);
+
+	/* get the chip type */
+	rev_type = readreg(dev, PRODUCT_ID_ADD);
+	lp->chip_type = rev_type &~ REVISON_BITS;
+	lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
+
+	/* Check the chip type and revision in order to set the correct send command
+	CS8920 revision C and CS8900 revision F can use the faster send. */
+	lp->send_cmd = TX_AFTER_381;
+	if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
+		lp->send_cmd = TX_NOW;
+	if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
+		lp->send_cmd = TX_NOW;
+
+	if (net_debug && version_printed++ == 0)
+		printk(version);
+
+	printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx",
+	       dev->name,
+	       lp->chip_type==CS8900?'0':'2',
+	       lp->chip_type==CS8920M?"M":"",
+	       lp->chip_revision,
+	       dev->base_addr);
+
+	/* Try to read the MAC address */
+	if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
+		printk("\nmac89x0: No EEPROM, giving up now.\n");
+		return ENODEV;
+        } else {
+                for (i = 0; i < ETH_ALEN; i += 2) {
+			/* Big-endian (why??!) */
+			unsigned short s = readreg(dev, PP_IA + i);
+                        dev->dev_addr[i] = s >> 8;
+                        dev->dev_addr[i+1] = s & 0xff;
+                }
+        }
+
+	dev->irq = SLOT2IRQ(slot);
+	printk(" IRQ %d ADDR ", dev->irq);
+
+	/* print the ethernet address. */
+	for (i = 0; i < ETH_ALEN; i++)
+		printk("%2.2x%s", dev->dev_addr[i],
+		       ((i < ETH_ALEN-1) ? ":" : ""));
+
+	dev->open		= net_open;
+	dev->stop		= net_close;
+	dev->hard_start_xmit = net_send_packet;
+	dev->get_stats	= net_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->set_mac_address = &set_mac_address;
+
+	/* Fill in the fields of the net_device structure with ethernet values. */
+	ether_setup(dev);
+
+	printk("\n");
+	return 0;
+}
+
+/* This is useful for something, but I don't know what yet. */
+void __init reset_chip(struct net_device *dev)
+{
+	int reset_start_time;
+
+	writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
+
+	/* wait 30 ms */
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(30*HZ/1000);
+
+	/* Wait until the chip is reset */
+	reset_start_time = jiffies;
+	while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
+		;
+}
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine should set everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+   */
+static int
+net_open(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int i;
+
+	/* Disable the interrupt for now */
+	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);
+
+	/* Grab the interrupt */
+	if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev))
+		return -EAGAIN;
+
+	/* Set up the IRQ - Apparently magic */
+	if (lp->chip_type == CS8900)
+		writereg(dev, PP_CS8900_ISAINT, 0);
+	else
+		writereg(dev, PP_CS8920_ISAINT, 0);
+
+	/* set the Ethernet address */
+	for (i=0; i < ETH_ALEN/2; i++)
+		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+	/* Turn on both receive and transmit operations */
+	writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
+
+	/* Receive only error free packets addressed to this card */
+	lp->rx_mode = 0;
+	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
+
+	lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
+
+	writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
+
+	writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
+	       TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
+
+	writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
+		 TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
+
+	/* now that we've got our act together, enable everything */
+	writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+        MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	if (dev->tbusy) {
+		/* If we get here, some higher level has decided we are broken.
+		   There should really be a "kick me" function call instead. */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 5)
+			return 1;
+		if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
+			   tx_done(dev) ? "IRQ conflict" : "network cable problem");
+		/* Try to restart the adaptor. */
+		dev->tbusy=0;
+		dev->trans_start = jiffies;
+	}
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+		printk("%s: Transmitter access conflict.\n", dev->name);
+	else {
+		struct net_local *lp = (struct net_local *)dev->priv;
+		unsigned long flags;
+
+		if (net_debug > 3)
+			printk("%s: sent %d byte packet of type %x\n",
+			       dev->name, skb->len,
+			       (skb->data[ETH_ALEN+ETH_ALEN] << 8)
+			       | skb->data[ETH_ALEN+ETH_ALEN+1]);
+
+		/* keep the upload from being interrupted, since we
+                   ask the chip to start transmitting before the
+                   whole packet has been completely uploaded. */
+		save_flags(flags);
+		cli();
+
+		/* initiate a transmit sequence */
+		writereg(dev, PP_TxCMD, lp->send_cmd);
+		writereg(dev, PP_TxLength, skb->len);
+
+		/* Test to see if the chip has allocated memory for the packet */
+		if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+			/* Gasp!  It hasn't.  But that shouldn't happen since
+			   we're waiting for TxOk, so return 1 and requeue this packet. */
+			restore_flags(flags);
+			return 1;
+		}
+
+		/* Write the contents of the packet */
+		memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
+
+		restore_flags(flags);
+		dev->trans_start = jiffies;
+	}
+	dev_kfree_skb (skb);
+
+	return 0;
+}
+
+/* The typical workload of the driver:
+   Handle the network interface interrupts. */
+static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = dev_id;
+	struct net_local *lp;
+	int ioaddr, status;
+
+	if (dev == NULL) {
+		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+	dev->interrupt = 1;
+
+	ioaddr = dev->base_addr;
+	lp = (struct net_local *)dev->priv;
+
+	/* we MUST read all the events out of the ISQ, otherwise we'll never
+           get interrupted again.  As a consequence, we can't have any limit
+           on the number of times we loop in the interrupt handler.  The
+           hardware guarantees that eventually we'll run out of events.  Of
+           course, if you're on a slow machine, and packets are arriving
+           faster than you can read them off, you're screwed.  Hasta la
+           vista, baby!  */
+	while ((status = swab16(readw(dev->base_addr + ISQ_PORT)))) {
+		if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
+		switch(status & ISQ_EVENT_MASK) {
+		case ISQ_RECEIVER_EVENT:
+			/* Got a packet(s). */
+			net_rx(dev);
+			break;
+		case ISQ_TRANSMITTER_EVENT:
+			lp->stats.tx_packets++;
+			dev->tbusy = 0;
+			mark_bh(NET_BH);	/* Inform upper layers. */
+			if ((status & TX_OK) == 0) lp->stats.tx_errors++;
+			if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
+			if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
+			if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
+			if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
+			break;
+		case ISQ_BUFFER_EVENT:
+			if (status & READY_FOR_TX) {
+				/* we tried to transmit a packet earlier,
+                                   but inexplicably ran out of buffers.
+                                   That shouldn't happen since we only ever
+                                   load one packet.  Shrug.  Do the right
+                                   thing anyway. */
+				dev->tbusy = 0;
+				mark_bh(NET_BH);	/* Inform upper layers. */
+			}
+			if (status & TX_UNDERRUN) {
+				if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
+                                lp->send_underrun++;
+                                if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
+                                else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
+                        }
+			break;
+		case ISQ_RX_MISS_EVENT:
+			lp->stats.rx_missed_errors += (status >>6);
+			break;
+		case ISQ_TX_COL_EVENT:
+			lp->stats.collisions += (status >>6);
+			break;
+		}
+	}
+	dev->interrupt = 0;
+	return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	struct sk_buff *skb;
+	int status, length;
+
+	status = readreg(dev, PP_RxStatus);
+	if ((status & RX_OK) == 0) {
+		lp->stats.rx_errors++;
+		if (status & RX_RUNT) lp->stats.rx_length_errors++;
+		if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
+		if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
+			/* per str 172 */
+			lp->stats.rx_crc_errors++;
+		if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
+		return;
+	}
+
+	length = readreg(dev, PP_RxLength);
+	/* Malloc up new buffer. */
+	skb = alloc_skb(length, GFP_ATOMIC);
+	if (skb == NULL) {
+		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+		lp->stats.rx_dropped++;
+		return;
+	}
+	skb->len = length;
+	skb->dev = dev;
+
+	memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length);
+
+	if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
+                                 dev->name, length,
+                                 (skb->data[ETH_ALEN+ETH_ALEN] << 8)
+				 | skb->data[ETH_ALEN+ETH_ALEN+1]);
+
+        skb->protocol=eth_type_trans(skb,dev);
+	netif_rx(skb);
+	lp->stats.rx_packets++;
+	lp->stats.rx_bytes+=skb->len;
+	return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+net_close(struct net_device *dev)
+{
+
+	writereg(dev, PP_RxCFG, 0);
+	writereg(dev, PP_TxCFG, 0);
+	writereg(dev, PP_BufCFG, 0);
+	writereg(dev, PP_BusCTL, 0);
+
+	dev->start = 0;
+
+	free_irq(dev->irq, dev);
+
+	/* Update the statistics here. */
+
+        MOD_DEC_USE_COUNT;
+	return 0;
+
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct net_device_stats *
+net_get_stats(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	cli();
+	/* Update the statistics from the device registers. */
+	lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
+	lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
+	sti();
+
+	return &lp->stats;
+}
+
+static void set_multicast_list(struct net_device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	if(dev->flags&IFF_PROMISC)
+	{
+		lp->rx_mode = RX_ALL_ACCEPT;
+	}
+	else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
+	{
+		/* The multicast-accept list is initialized to accept-all, and we
+		   rely on higher-level filtering for now. */
+		lp->rx_mode = RX_MULTCAST_ACCEPT;
+	} 
+	else
+		lp->rx_mode = 0;
+
+	writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
+
+	/* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
+	writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
+	     (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
+}
+
+
+static int set_mac_address(struct net_device *dev, void *addr)
+{
+	int i;
+	if (dev->start)
+		return -EBUSY;
+	printk("%s: Setting MAC address to ", dev->name);
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+	printk(".\n");
+	/* set the Ethernet address */
+	for (i=0; i < ETH_ALEN/2; i++)
+		writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
+
+	return 0;
+}
+
+#ifdef MODULE
+
+static char namespace[16] = "";
+static struct net_device dev_cs89x0 = {
+        NULL,
+        0, 0, 0, 0,
+        0, 0,
+        0, 0, 0, NULL, NULL };
+
+static int debug=0;
+
+MODULE_PARM(debug, "i");
+
+EXPORT_NO_SYMBOLS;
+
+int
+init_module(void)
+{
+	struct net_local *lp;
+
+	net_debug = debug;
+        dev_cs89x0.name = namespace;
+        dev_cs89x0.init = mac89x0_probe;
+        dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
+	lp = (struct net_local *)dev_cs89x0.priv;
+
+        if (register_netdev(&dev_cs89x0) != 0) {
+                printk(KERN_WARNING "mac89x0.c: No card found\n");
+                return -ENXIO;
+        }
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+
+#endif
+#ifdef MODULE
+	writew(0, dev_cs89x0.base_addr + ADD_PORT);
+#endif
+#ifdef MODULE
+
+        if (dev_cs89x0.priv != NULL) {
+                /* Free up the private structure, or leak memory :-)  */
+                unregister_netdev(&dev_cs89x0);
+                kfree(dev_cs89x0.priv);
+                dev_cs89x0.priv = NULL;	/* gets re-allocated by cs89x0_probe1 */
+        }
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o mac89x0.o mac89x0.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ *
+ */
diff -u --recursive --new-file v2.3.41/linux/drivers/net/macmace.c linux/drivers/net/macmace.c
--- v2.3.41/linux/drivers/net/macmace.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/macmace.c	Mon Jan 31 10:34:12 2000
@@ -0,0 +1,825 @@
+/*
+ *	Driver for the Macintosh 68K onboard MACE controller with PSC
+ *	driven DMA. The MACE driver code is derived from mace.c. The
+ *	Mac68k theory of operation is courtesy of the MacBSD wizards.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Copyright (C) 1996 Paul Mackerras.
+ *	Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_psc.h>
+#include "mace.h"
+
+#define N_RX_RING	8
+#define N_TX_RING	2
+#define MAX_TX_ACTIVE	1
+#define NCMDS_TX	1	/* dma commands per element in tx ring */
+#define RX_BUFLEN	(ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT	HZ	/* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR	0x80
+
+/* The MACE is simply wired down on a Mac68K box */
+
+#define MACE_BASE	(void *)(0x50F1C000)
+#define MACE_PROM	(void *)(0x50F08001)
+
+struct mace68k_data
+{
+	volatile struct mace *mace;
+	volatile unsigned char *tx_ring;
+	volatile unsigned char *rx_ring;
+	int dma_intr;
+	unsigned char maccc;
+	struct net_device_stats stats;
+	struct timer_list tx_timeout;
+	int timeout_active;
+	int rx_slot, rx_done;
+	int tx_slot, tx_count;
+};
+
+struct mace_frame
+{
+	u16	len;
+	u16	status;
+	u16	rntpc;
+	u16	rcvcc;
+	u32	pad1;
+	u32	pad2;
+	u8	data[1];	
+	/* And frame continues.. */
+};
+
+#define PRIV_BYTES	sizeof(struct mace68k_data)
+
+extern void psc_debug_dump(void);
+
+static int mace68k_open(struct net_device *dev);
+static int mace68k_close(struct net_device *dev);
+static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *mace68k_stats(struct net_device *dev);
+static void mace68k_set_multicast(struct net_device *dev);
+static void mace68k_reset(struct net_device *dev);
+static int mace68k_set_address(struct net_device *dev, void *addr);
+static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace68k_set_timeout(struct net_device *dev);
+static void mace68k_tx_timeout(unsigned long data);
+
+/*
+ *	PSC DMA engine control. As you'd expect on a macintosh its
+ *	more like a lawnmower engine supplied without instructions
+ *
+ *	The basic theory of operation appears to be as follows.
+ *
+ *	There are two sets of receive DMA registers and two sets
+ *	of transmit DMA registers. Instead of the more traditional
+ *	"ring buffer" approach the Mac68K DMA engine expects you
+ *	to be loading one chain while the other runs, and then
+ *	to flip register set. Each entry in the chain is a fixed 
+ *	length.
+ */
+
+/*
+ *	Load a receive DMA channel with a base address and ring length
+ */
+  
+static void psc_load_rxdma_base(int set, void *base)
+{
+	psc_write_word(PSC_ENETRD_CMD + set, 0x0100);
+	psc_write_long(PSC_ENETRD_ADDR + set, (u32)base);
+	psc_write_long(PSC_ENETRD_LEN + set, N_RX_RING);
+	psc_write_word(PSC_ENETRD_CMD + set, 0x9800);
+}
+
+/*
+ *	Reset the receive DMA subsystem
+ */
+  
+static void mace68k_rxdma_reset(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mace = mp->mace;
+	u8 mcc = mace->maccc;
+	
+	/*
+	 *	Turn off receive
+	 */
+	 
+	mcc&=~ENRCV;
+	mace->maccc=mcc;
+	
+	/*
+	 *	Program the DMA
+	 */
+	
+	psc_write_word(PSC_ENETRD_CTL, 0x8800);
+	psc_load_rxdma_base(0x0, (void *)virt_to_bus(mp->rx_ring));
+	psc_write_word(PSC_ENETRD_CTL, 0x0400);
+	
+	psc_write_word(PSC_ENETRD_CTL, 0x8800);
+	psc_load_rxdma_base(0x10, (void *)virt_to_bus(mp->rx_ring));
+	psc_write_word(PSC_ENETRD_CTL, 0x0400);
+	
+	mace->maccc=mcc|ENRCV;
+	
+#if 0
+	psc_write_word(PSC_ENETRD_CTL, 0x9800);
+	psc_write_word(PSC_ENETRD_CTL+0x10, 0x9800);
+#endif
+}
+
+/*
+ *	Reset the transmit DMA subsystem
+ */
+ 
+static void mace68k_txdma_reset(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mace = mp->mace;
+	u8 mcc = mace->maccc;
+
+	psc_write_word(PSC_ENETWR_CTL,0x8800);
+	
+	mace->maccc = mcc&~ENXMT;
+	psc_write_word(PSC_ENETWR_CTL,0x0400);
+	mace->maccc = mcc;
+}
+
+/*
+ *	Disable DMA
+ */
+ 
+static void mace68k_dma_off(struct net_device *dev)
+{
+	psc_write_word(PSC_ENETRD_CTL, 0x8800);
+	psc_write_word(PSC_ENETRD_CTL, 0x1000);
+	psc_write_word(PSC_ENETRD_CMD, 0x1100);
+	psc_write_word(PSC_ENETRD_CMD+0x10, 0x1100);
+                                        
+	psc_write_word(PSC_ENETWR_CTL, 0x8800);
+	psc_write_word(PSC_ENETWR_CTL, 0x1000);
+	psc_write_word(PSC_ENETWR_CMD, 0x1100);
+	psc_write_word(PSC_ENETWR_CMD+0x10, 0x1100);
+}
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+
+static int bitrev(int b)
+{
+    int d = 0, i;
+
+    for (i = 0; i < 8; ++i, b >>= 1)
+	d = (d << 1) | (b & 1);
+    return d;
+}
+
+/*
+ * 	Not really much of a probe. The hardware table tells us if this
+ *	model of Macintrash has a MACE (AV macintoshes)
+ */
+ 
+int mace68k_probe(struct net_device *unused)
+{
+	int j;
+	static int once=0;
+	struct mace68k_data *mp;
+	unsigned char *addr;
+	struct net_device *dev;
+	unsigned char checksum = 0;
+	
+	/*
+	 *	There can be only one...
+	 */
+	 
+	if (once) return -ENODEV;
+	
+	once = 1;
+
+	if (macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV;
+
+	printk("MACE ethernet should be present ");
+	
+	dev = init_etherdev(0, PRIV_BYTES);
+	if(dev==NULL)
+	{
+		printk("no free memory.\n");
+		return -ENOMEM;
+	}		
+	mp = (struct mace68k_data *) dev->priv;
+	dev->base_addr = (u32)MACE_BASE;
+	mp->mace = (volatile struct mace *) MACE_BASE;
+	
+	printk("at 0x%p", mp->mace);
+	
+	/*
+	 *	16K RX ring and 4K TX ring should do nicely
+	 */
+
+	mp->rx_ring=(void *)__get_free_pages(GFP_KERNEL, 2);
+	mp->tx_ring=(void *)__get_free_page(GFP_KERNEL);
+	
+	printk(".");
+	
+	if(mp->tx_ring==NULL || mp->rx_ring==NULL)
+	{
+		if(mp->tx_ring)
+			free_page((u32)mp->tx_ring);
+//		if(mp->rx_ring)
+//			__free_pages(mp->rx_ring,2);
+		printk("\nNo memory for ring buffers.\n");
+		return -ENOMEM;
+	}
+
+	/* We want the receive data to be uncached. We dont care about the
+	   byte reading order */
+
+	printk(".");	
+	kernel_set_cachemode((void *)mp->rx_ring, 16384, IOMAP_NOCACHE_NONSER);	
+	
+	printk(".");	
+	/* The transmit buffer needs to be write through */
+	kernel_set_cachemode((void *)mp->tx_ring, 4096, IOMAP_WRITETHROUGH);
+
+	printk(" Ok\n");	
+	dev->irq = IRQ_MAC_MACE;
+	printk(KERN_INFO "%s: MACE at", dev->name);
+
+	/*
+	 *	The PROM contains 8 bytes which total 0xFF when XOR'd
+	 *	together. Due to the usual peculiar apple brain damage
+	 *	the bytes are spaced out in a strange boundary and the
+	 * 	bits are reversed.
+	 */
+
+	addr = (void *)MACE_PROM;
+		 
+	for (j = 0; j < 6; ++j)
+	{
+		u8 v=bitrev(addr[j<<4]);
+		checksum^=v;
+		dev->dev_addr[j] = v;
+		printk("%c%.2x", (j ? ':' : ' '), dev->dev_addr[j]);
+	}
+	for (; j < 8; ++j)
+	{
+		checksum^=bitrev(addr[j<<4]);
+	}
+	
+	if(checksum!=0xFF)
+	{
+		printk(" (invalid checksum)\n");
+		return -ENODEV;
+	}		
+	printk("\n");
+
+	memset(&mp->stats, 0, sizeof(mp->stats));
+	init_timer(&mp->tx_timeout);
+	mp->timeout_active = 0;
+
+	dev->open = mace68k_open;
+	dev->stop = mace68k_close;
+	dev->hard_start_xmit = mace68k_xmit_start;
+	dev->get_stats = mace68k_stats;
+	dev->set_multicast_list = mace68k_set_multicast;
+	dev->set_mac_address = mace68k_set_address;
+
+	ether_setup(dev);
+
+	mp = (struct mace68k_data *) dev->priv;
+	mp->maccc = ENXMT | ENRCV;
+	mp->dma_intr = IRQ_MAC_MACE_DMA;
+
+	psc_write_word(PSC_ENETWR_CTL, 0x9000);
+	psc_write_word(PSC_ENETRD_CTL, 0x9000);
+	psc_write_word(PSC_ENETWR_CTL, 0x0400);
+	psc_write_word(PSC_ENETRD_CTL, 0x0400);
+                                        	
+	/* apple's driver doesn't seem to do this */
+	/* except at driver shutdown time...      */
+#if 0
+	mace68k_dma_off(dev);
+#endif
+
+	return 0;
+}
+
+/*
+ *	Reset a MACE controller
+ */
+ 
+static void mace68k_reset(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mb = mp->mace;
+	int i;
+
+	/* soft-reset the chip */
+	i = 200;
+	while (--i) {
+		mb->biucc = SWRST;
+		if (mb->biucc & SWRST) {
+			udelay(10);
+			continue;
+		}
+		break;
+	}
+	if (!i) {
+		printk(KERN_ERR "mace: cannot reset chip!\n");
+		return;
+	}
+
+	mb->biucc = XMTSP_64;
+	mb->imr = 0xff;		/* disable all intrs for now */
+	i = mb->ir;
+	mb->maccc = 0;		/* turn off tx, rx */
+	mb->utr = RTRD;
+	mb->fifocc = RCVFW_64;
+	mb->xmtfc = AUTO_PAD_XMIT;	/* auto-pad short frames */
+
+	/* load up the hardware address */
+	
+	mb->iac = ADDRCHG | PHYADDR;
+	
+	while ((mb->iac & ADDRCHG) != 0);
+	
+	for (i = 0; i < 6; ++i)
+		mb->padr = dev->dev_addr[i];
+
+	/* clear the multicast filter */
+	mb->iac = ADDRCHG | LOGADDR;
+
+	while ((mb->iac & ADDRCHG) != 0);
+	
+	for (i = 0; i < 8; ++i)
+		mb->ladrf = 0;
+
+	mb->plscc = PORTSEL_GPSI + ENPLSIO;
+}
+
+/*
+ *	Load the address on a mace controller.
+ */
+ 
+static int mace68k_set_address(struct net_device *dev, void *addr)
+{
+	unsigned char *p = addr;
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mb = mp->mace;
+	int i;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	/* load up the hardware address */
+	mb->iac = ADDRCHG | PHYADDR;
+	while ((mb->iac & ADDRCHG) != 0);
+	
+	for (i = 0; i < 6; ++i)
+		mb->padr = dev->dev_addr[i] = p[i];
+	/* note: setting ADDRCHG clears ENRCV */
+	mb->maccc = mp->maccc;
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ *	Open the Macintosh MACE. Most of this is playing with the DMA
+ *	engine. The ethernet chip is quite friendly.
+ */
+ 
+static int mace68k_open(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mb = mp->mace;
+
+	/* reset the chip */
+	mace68k_reset(dev);
+
+	mp->rx_done = 0;
+	mace68k_rxdma_reset(dev);
+
+	/*
+	 *	The interrupt is fixed and comes off the PSC.
+	 */
+	 
+	if (request_irq(dev->irq, mace68k_interrupt, 0, "68K MACE", dev))
+	{
+		printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
+		return -EAGAIN;
+	}
+
+	/*
+	 *	Ditto the DMA interrupt.
+	 */
+	 
+	if (request_irq(IRQ_MAC_MACE_DMA, mace68k_dma_intr, 0, "68K MACE DMA",
+			dev))
+	{
+		printk(KERN_ERR "MACE: can't get irq %d\n", IRQ_MAC_MACE_DMA);
+		return -EAGAIN;
+	}
+
+	/* Activate the Mac DMA engine */
+
+	mp->tx_slot = 0;		/* Using register set 0 */
+	mp->tx_count = 1;		/* 1 Buffer ready for use */
+	mace68k_txdma_reset(dev);
+	
+	/* turn it on! */
+	mb->maccc = mp->maccc;
+	/* enable all interrupts except receive interrupts */
+	mb->imr = RCVINT;
+	return 0;
+}
+
+/*
+ *	Shut down the mace and its interrupt channel
+ */
+ 
+static int mace68k_close(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mb = mp->mace;
+
+	/* disable rx and tx */
+	mb->maccc = 0;
+	mb->imr = 0xff;		/* disable all intrs */
+
+	/* disable rx and tx dma */
+
+	mace68k_dma_off(dev);
+
+	free_irq(dev->irq, dev);
+	free_irq(IRQ_MAC_MACE_DMA, dev);
+	return 0;
+}
+
+static inline void mace68k_set_timeout(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (mp->timeout_active)
+		del_timer(&mp->tx_timeout);
+	mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+	mp->tx_timeout.function = mace68k_tx_timeout;
+	mp->tx_timeout.data = (unsigned long) dev;
+	add_timer(&mp->tx_timeout);
+	mp->timeout_active = 1;
+	restore_flags(flags);
+}
+
+/*
+ *	Transmit a frame
+ */
+ 
+static int mace68k_xmit_start(struct sk_buff *skb, struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	/*
+	 *	This may need atomic types ???
+	 */
+
+	printk("mace68k_xmit_start: mp->tx_count = %d, dev->tbusy = %d, mp->tx_ring = %p (%p)\n",
+		mp->tx_count, dev->tbusy,
+		mp->tx_ring, virt_to_bus(mp->tx_ring));
+	psc_debug_dump();
+
+	if(mp->tx_count == 0)
+	{
+		dev->tbusy=1;
+		mace68k_dma_intr(IRQ_MAC_MACE_DMA, dev, NULL);
+		return 1;
+	}
+	mp->tx_count--;
+	
+	/*
+	 *	FIXME:
+	 *	This is hackish. The memcpy probably isnt needed but
+	 *	the rules for alignment are not known. Ideally we'd like
+	 *	to just blast the skb directly to ethernet. We also don't
+	 *	use the ring properly - just a one frame buffer. That
+	 *	also requires cache pushes ;).
+	 */
+	memcpy((void *)mp->tx_ring, skb, skb->len);
+	psc_write_long(PSC_ENETWR_ADDR + mp->tx_slot, virt_to_bus(mp->tx_ring));
+        psc_write_long(PSC_ENETWR_LEN + mp->tx_slot, skb->len);
+        psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x9800);                       
+	mp->stats.tx_packets++;
+	mp->stats.tx_bytes+=skb->len;
+        dev_kfree_skb(skb);
+	return 0;
+}
+
+static struct net_device_stats *mace68k_stats(struct net_device *dev)
+{
+	struct mace68k_data *p = (struct mace68k_data *) dev->priv;
+	return &p->stats;
+}
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define CRC_POLY	0xedb88320
+
+static void mace68k_set_multicast(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mb = mp->mace;
+	int i, j, k, b;
+	unsigned long crc;
+
+	mp->maccc &= ~PROM;
+	if (dev->flags & IFF_PROMISC)
+	{
+		mp->maccc |= PROM;
+	} else
+	{
+		unsigned char multicast_filter[8];
+		struct dev_mc_list *dmi = dev->mc_list;
+
+		if (dev->flags & IFF_ALLMULTI)
+		{
+			for (i = 0; i < 8; i++)
+				multicast_filter[i] = 0xff;
+		} else
+		{
+			for (i = 0; i < 8; i++)
+				multicast_filter[i] = 0;
+			for (i = 0; i < dev->mc_count; i++)
+			{
+				crc = ~0;
+				for (j = 0; j < 6; ++j)
+				{
+					b = dmi->dmi_addr[j];
+					for (k = 0; k < 8; ++k)
+					{
+						if ((crc ^ b) & 1)
+							crc = (crc >> 1) ^ CRC_POLY;
+						else
+							crc >>= 1;
+						b >>= 1;
+					}
+				}
+				j = crc >> 26;	/* bit number in multicast_filter */
+				multicast_filter[j >> 3] |= 1 << (j & 7);
+				dmi = dmi->next;
+			}
+		}
+#if 0
+		printk("Multicast filter :");
+		for (i = 0; i < 8; i++)
+			printk("%02x ", multicast_filter[i]);
+		printk("\n");
+#endif
+
+		mb->iac = ADDRCHG | LOGADDR;
+		while ((mb->iac & ADDRCHG) != 0);
+		
+		for (i = 0; i < 8; ++i)
+			mb->ladrf = multicast_filter[i];
+	}
+	/* reset maccc */
+	mb->maccc = mp->maccc;
+}
+
+/*
+ *	Miscellaneous interrupts are handled here. We may end up 
+ *	having to bash the chip on the head for bad errors
+ */
+ 
+static void mace68k_handle_misc_intrs(struct mace68k_data *mp, int intr)
+{
+	volatile struct mace *mb = mp->mace;
+	static int mace68k_babbles, mace68k_jabbers;
+
+	if (intr & MPCO)
+		mp->stats.rx_missed_errors += 256;
+	mp->stats.rx_missed_errors += mb->mpc;	/* reading clears it */
+	if (intr & RNTPCO)
+		mp->stats.rx_length_errors += 256;
+	mp->stats.rx_length_errors += mb->rntpc;	/* reading clears it */
+	if (intr & CERR)
+		++mp->stats.tx_heartbeat_errors;
+	if (intr & BABBLE)
+		if (mace68k_babbles++ < 4)
+			printk(KERN_DEBUG "mace: babbling transmitter\n");
+	if (intr & JABBER)
+		if (mace68k_jabbers++ < 4)
+			printk(KERN_DEBUG "mace: jabbering transceiver\n");
+}
+
+/*
+ *	A transmit error has occured. (We kick the transmit side from
+ *	the DMA completion)
+ */
+ 
+static void mace68k_xmit_error(struct net_device *dev)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mb = mp->mace;
+	u8 xmtfs, xmtrc;
+	
+	xmtfs = mb->xmtfs;
+	xmtrc = mb->xmtrc;
+	
+	if(xmtfs & XMTSV)
+	{
+		if(xmtfs & UFLO)
+		{
+			printk("%s: DMA underrun.\n", dev->name);
+			mp->stats.tx_errors++;
+			mp->stats.tx_fifo_errors++;
+			mace68k_reset(dev);
+		}
+		if(xmtfs & RTRY)
+			mp->stats.collisions++;
+	}			
+	mark_bh(NET_BH);
+}
+
+/*
+ *	A receive interrupt occured.
+ */
+ 
+static void mace68k_recv_interrupt(struct net_device *dev)
+{
+//	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+//	volatile struct mace *mb = mp->mace;
+}
+
+/*
+ *	Process the chip interrupt
+ */
+ 
+static void mace68k_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	volatile struct mace *mb = mp->mace;
+	u8 ir;
+	
+	ir = mb->ir;
+	mace68k_handle_misc_intrs(mp, ir);
+	
+	if(ir&XMTINT)
+		mace68k_xmit_error(dev);
+	if(ir&RCVINT)
+		mace68k_recv_interrupt(dev);
+}
+
+static void mace68k_tx_timeout(unsigned long data)
+{
+//	struct net_device *dev = (struct net_device *) data;
+//	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+//	volatile struct mace *mb = mp->mace;
+}
+
+/*
+ *	Handle a newly arrived frame
+ */
+ 
+static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
+{
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+	struct sk_buff *skb;
+
+	if(mf->status&RS_OFLO)
+	{
+		printk("%s: fifo overflow.\n", dev->name);
+		mp->stats.rx_errors++;
+		mp->stats.rx_fifo_errors++;
+	}
+	if(mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR))
+		mp->stats.rx_errors++;
+		
+	if(mf->status&RS_CLSN)
+		mp->stats.collisions++;
+	if(mf->status&RS_FRAMERR)
+		mp->stats.rx_frame_errors++;
+	if(mf->status&RS_FCSERR)
+		mp->stats.rx_crc_errors++;
+		
+	skb = dev_alloc_skb(mf->len+2);
+	if(skb==NULL)
+	{
+		mp->stats.rx_dropped++;
+		return;
+	}
+	skb_reserve(skb,2);
+	memcpy(skb_put(skb, mf->len), mf->data, mf->len);
+	
+	skb->protocol = eth_type_trans(skb, dev);
+	netif_rx(skb);
+	mp->stats.rx_packets++;
+	mp->stats.rx_bytes+=mf->len;
+}
+
+/*
+ *	The PSC has passed us a DMA interrupt event.
+ */
+ 
+static void mace68k_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct mace68k_data *mp = (struct mace68k_data *) dev->priv;
+
+#if 0
+	u32 psc_status;
+	
+	/* It seems this must be allowed to stabilise ?? */
+	
+	while((psc_status=psc_read_long(0x0804))!=psc_read_long(0x0804));
+
+	/*
+	 *	Was this an ethernet event ?
+	 */
+	 	
+	if(psc_status&0x60000000)
+	{
+#endif
+		/*
+		 *	Process the read queue
+		 */
+		 
+		u16 psc_status = psc_read_word(PSC_ENETRD_CTL);
+		
+		printk("mace68k_dma_intr: PSC_ENETRD_CTL = %04X\n", (uint) psc_status);
+
+		if (psc_status & 0x2000) {
+			mace68k_rxdma_reset(dev);
+			mp->rx_done = 0;
+		} else if (psc_status & 0x100) {
+			int left;
+			
+			psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x1100);
+			left=psc_read_long(PSC_ENETRD_LEN + mp->rx_slot);
+			/* read packets */	
+			
+			while(mp->rx_done < left)
+			{
+				struct mace_frame *mf=((struct mace_frame *)
+					mp->rx_ring)+mp->rx_done++;
+				mace_dma_rx_frame(dev, mf);
+			}
+			
+			if(left == 0)	/* Out of DMA room */
+			{
+				psc_load_rxdma_base(mp->rx_slot, 
+					(void *)virt_to_phys(mp->rx_ring));
+				mp->rx_slot^=16;
+				mp->rx_done = 0;
+			}
+			else
+			{
+				psc_write_word(PSC_ENETRD_CMD+mp->rx_slot,
+					0x9800);
+			}
+					
+		}
+		
+		/*
+		 *	Process the write queue
+		 */
+		 
+		psc_status = psc_read_word(PSC_ENETWR_CTL);
+		printk("mace68k_dma_intr: PSC_ENETWR_CTL = %04X\n", (uint) psc_status);
+
+		/* apple's driver seems to loop over this until neither */
+		/* condition is true.    - jmt                          */
+
+		if (psc_status & 0x2000) {
+			mace68k_txdma_reset(dev);
+		} else if (psc_status & 0x0100) {
+			psc_write_word(PSC_ENETWR_CMD + mp->tx_slot, 0x0100);
+			mp->tx_slot ^=16;
+			mp->tx_count++;
+			dev->tbusy = 0;
+			mark_bh(NET_BH);
+		}
+#if 0
+	}
+#endif
+}
diff -u --recursive --new-file v2.3.41/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c
--- v2.3.41/linux/drivers/net/macsonic.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/macsonic.c	Mon Jan 31 23:43:51 2000
@@ -42,153 +42,245 @@
 #include <asm/pgtable.h>
 #include <asm/segment.h>
 #include <asm/io.h>
+#include <asm/hwtest.h>
 #include <asm/dma.h>
 #include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/mac_via.h>
 
 #include <linux/errno.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-
-#include <config/macsonic.h>
+#include <linux/module.h>
 
 #define SREGS_PAD(n)    u16 n;
 
 #include "sonic.h"
 
-extern int mac_onboard_sonic_probe(void);
+static int sonic_debug = 0;
+static int sonic_version_printed = 0;
 
-static int setup_debug = -1;
-static int setup_offset = -1;
-static int setup_shift = -1;
+extern int macsonic_probe(struct net_device* dev);
+extern int mac_onboard_sonic_probe(struct net_device* dev);
+extern int mac_nubus_sonic_probe(struct net_device* dev);
+
+/* For onboard SONIC */
+#define ONBOARD_SONIC_REGISTERS	0x50F0A000
+#define ONBOARD_SONIC_PROM_BASE	0x50f08000
+
+enum macsonic_type {
+	MACSONIC_DUODOCK,
+	MACSONIC_APPLE,
+	MACSONIC_APPLE16,
+	MACSONIC_DAYNA,
+	MACSONIC_DAYNALINK
+};
+
+/* For the built-in SONIC in the Duo Dock */
+#define DUODOCK_SONIC_REGISTERS 0xe10000
+#define DUODOCK_SONIC_PROM_BASE 0xe12000
+
+/* For Apple-style NuBus SONIC */
+#define APPLE_SONIC_REGISTERS	0
+#define APPLE_SONIC_PROM_BASE	0x40000
+
+/* Daynalink LC SONIC */
+#define DAYNALINK_PROM_BASE 0x400000
+
+/* For Dayna-style NuBus SONIC (haven't seen one yet) */
+#define DAYNA_SONIC_REGISTERS   0x180000
+/* This is what OpenBSD says.  However, this is definitely in NuBus
+   ROM space so we should be able to get it by walking the NuBus
+   resource directories */
+#define DAYNA_SONIC_MAC_ADDR	0xffe004
 
-/*
- * This seems to be the right default for the Q800
- */
+#define SONIC_READ_PROM(addr) readb(prom_addr+addr)
 
-static int reg_offset = 0;
-static int reg_shift = 0;
+int __init macsonic_probe(struct net_device* dev)
+{
+	int rv;
 
-/*
- * Macros to access SONIC registers
- */
- 
-#define MAC_SONIC_REGISTERS	0x50F0A000
-#define MAC_SONIC_PROM_BASE	0x50f08000
-#define MAC_SONIC_IRQ		9	/* Nubus 9 */
+	/* This will catch fatal stuff like -ENOMEM as well as success */
+	if ((rv = mac_onboard_sonic_probe(dev)) != -ENODEV)
+		return rv;
+	return mac_nubus_sonic_probe(dev);
+}
 
 /*
- *    FIXME: We may need to invert the byte ordering. These should
- *      be ok for other aspects as they are uncached spaces.
- *      The original macros from jazzsonic.c works for me
- *      on my LC 630, YMMV /Andreas Ehliar
+ * For reversing the PROM address
  */
 
-#if 0
-#define SONIC_READ(reg) \
-	*((volatile unsigned int *)base_addr+((reg)<<2)+2)
+static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
+				    1, 9, 5, 13, 3, 11, 7, 15};
 
-#define SONIC_WRITE(reg,val) \
-	*((volatile unsigned int *)base_addr+((reg)<<2)+2) = val
-#else
-#define SONIC_READ(reg) \
-	*((volatile unsigned int *)base_addr+reg)
+static inline void bit_reverse_addr(unsigned char addr[6])
+{
+	int i;
 
-#define SONIC_WRITE(reg,val) \
-	*((volatile unsigned int *)base_addr+reg) = val
-#endif
+	for(i = 0; i < 6; i++)
+		addr[i] = ((nibbletab[addr[i] & 0xf] << 4) | 
+			   nibbletab[(addr[i] >> 4) &0xf]);
+}
 
-#define SONIC_READ_PROM(addr) \
-	*((volatile unsigned char *)prom_addr+addr)
-/*
- * Function : mac_sonic_setup(char *str, int *ints)
- *
- * Purpose : booter command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
- *
- * Currently unused in the new driver; need to add settable parameters to the 
- * detect function.
- *
- */
+int __init macsonic_init(struct net_device* dev)
+{
+	struct sonic_local* lp = (struct sonic_local *)dev->priv;
+	int i;
 
-void mac_sonic_setup(char *str, int *ints) {
-	/* Format of macsonic parameter is:
-	 *   macsonic=<debug>,<offset>,<shift>
-	 * Negative values mean don't change.
-	 */
-	
-	/* Grmbl... the standard parameter parsing can't handle negative numbers
-	 * :-( So let's do it ourselves!
-	 */
+	/* Allocate the entire chunk of memory for the descriptors.
+           Note that this cannot cross a 64K boundary. */
+	for (i = 0; i < 20; i++) {
+		unsigned long desc_base, desc_top;
+		if ((lp->sonic_desc = 
+		     kmalloc(SIZEOF_SONIC_DESC
+			     * SONIC_BUS_SCALE(lp->dma_bitmode), GFP_DMA)) == NULL) {
+			printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name);
+		}
+		desc_base = (unsigned long) lp->sonic_desc;
+		desc_top = desc_base + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode);
+		if ((desc_top & 0xffff) >= (desc_base & 0xffff))
+			break;
+		/* Hmm. try again (FIXME: does this actually work?) */
+		kfree(lp->sonic_desc);
+		printk(KERN_DEBUG
+		       "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n",
+		       dev->name, desc_base, desc_top);
+	}
+
+	if (lp->sonic_desc == NULL) {
+		printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n",
+		       dev->name);
+		return -ENOMEM;
+	}		       
 
-	int i = ints[0]+1, fact;
+	/* Now set up the pointers to point to the appropriate places */
+	lp->cda = lp->sonic_desc;
+	lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode));
+	lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS
+			     * SONIC_BUS_SCALE(lp->dma_bitmode));
+	lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+			     * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+	/* FIXME, maybe we should use skbs */
+	if ((lp->rba = (char *)
+	     kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_DMA)) == NULL) {
+		printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
+		return -ENOMEM;
+	}
 
-	while( str && (isdigit(*str) || *str == '-') && i <= 10) {
-		if (*str == '-')
-			fact = -1, ++str;
-		else
-			fact = 1;
-		ints[i++] = simple_strtoul( str, NULL, 0 ) * fact;
-		if ((str = strchr( str, ',' )) != NULL)
-			++str;
+	{
+		int rs, ds;
+
+		/* almost always 12*4096, but let's not take chances */
+		rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096;
+		/* almost always under a page, but let's not take chances */
+		ds = ((SIZEOF_SONIC_DESC + 4095) / 4096) * 4096;
+		kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER);
+		kernel_set_cachemode(lp->sonic_desc, ds, IOMAP_NOCACHE_SER);
 	}
-	ints[0] = i-1;
 	
-	if (ints[0] < 1) {
-		printk( "mac_sonic_setup: no arguments!\n" );
-		return;
-	}
-
-	if (ints[0] >= 1) {
-	       	/* 0 <= n <= 2 */
-		if (ints[1] >= 0 && ints[1] <= 8)
-			setup_debug = ints[1];
-		else if (ints[1] > 16)
-			printk( "mac_sonic_setup: invalid debug level %d !\n", ints[1] );
-	}
-	if (ints[0] >= 2) {
-	       	/* 0 <= n <= 2 */
-		if (ints[2] >= 0 && ints[2] <= 16)
-			setup_offset = ints[2];
-		else if (ints[2] > 16)
-			printk( "mac_sonic_setup: invalid offset %d !\n", ints[2] );
-	}
-	if (ints[0] >= 3) {
-	       	/* 0 <= n <= 2 */
-		if (ints[3] >= 0 && ints[3] <= 16)
-			setup_shift = ints[3];
-		else if (ints[3] > 16)
-			printk( "mac_sonic_setup: invalid shift %d !\n", ints[3] );
-	}
+#if 0
+	flush_cache_all();
+#endif
+
+	dev->open = sonic_open;
+	dev->stop = sonic_close;
+	dev->hard_start_xmit = sonic_send_packet;
+	dev->get_stats = sonic_get_stats;
+	dev->set_multicast_list = &sonic_multicast_list;
+
+	/*
+	 * clear tally counter
+	 */
+	sonic_write(dev, SONIC_CRCT, 0xffff);
+	sonic_write(dev, SONIC_FAET, 0xffff);
+	sonic_write(dev, SONIC_MPT, 0xffff);
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+	return 0;
 }
 
-static int sonic_debug = 0;
+int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
+{
+	const int prom_addr = ONBOARD_SONIC_PROM_BASE;
+	int i;
 
-/*
- * For reversing the PROM address
- */
+	/* On NuBus boards we can sometimes look in the ROM resources.
+	   No such luck for comm-slot/onboard. */
+	for(i = 0; i < 6; i++)
+		dev->dev_addr[i] = SONIC_READ_PROM(i);
+
+	/* Most of the time, the address is bit-reversed.  The NetBSD
+	   source has a rather long and detailed historical account of
+	   why this is so. */
+	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+	    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+	    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+		bit_reverse_addr(dev->dev_addr);
+	else
+		return 0;
+
+	/* If we still have what seems to be a bogus address, we'll
+           look in the CAM.  The top entry should be ours. */
+	/* Danger! This only works if MacOS has already initialized
+           the card... */
+	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+	    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+	    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+	{
+		unsigned short val;
 
-static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
-				    1, 9, 5, 13, 3, 11, 7, 15};
+		printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
+		
+		sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
+		sonic_write(dev, SONIC_CEP, 15);
+
+		val = sonic_read(dev, SONIC_CAP2);
+		dev->dev_addr[5] = val >> 8;
+		dev->dev_addr[4] = val & 0xff;
+		val = sonic_read(dev, SONIC_CAP1);
+		dev->dev_addr[3] = val >> 8;
+		dev->dev_addr[2] = val & 0xff;
+		val = sonic_read(dev, SONIC_CAP0);
+		dev->dev_addr[1] = val >> 8;
+		dev->dev_addr[0] = val & 0xff;
+		
+		printk(KERN_INFO "HW Address from CAM 15: ");
+		for (i = 0; i < 6; i++) {
+			printk("%2.2x", dev->dev_addr[i]);
+			if (i < 5)
+				printk(":");
+		}
+		printk("\n");
+	} else return 0;
 
-int __init mac_onboard_sonic_probe(void)
+	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
+	    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
+	    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
+	{
+		/*
+		 * Still nonsense ... messed up someplace!
+		 */
+		printk(KERN_ERR "macsonic: ERROR (INVALID MAC)\n");
+		return -EIO;
+	} else return 0;
+}
+
+int __init mac_onboard_sonic_probe(struct net_device* dev)
 {
-	struct net_device *dev;
-	unsigned int silicon_revision;
-	unsigned int val;
-	struct sonic_local *lp;
+	/* Bwahahaha */
+	static int once_is_more_than_enough = 0;
+	struct sonic_local* lp;
 	int i;
-	int base_addr = MAC_SONIC_REGISTERS;
-	int prom_addr = MAC_SONIC_PROM_BASE;
-	static int one=0;
 	
-	if (!MACH_IS_MAC)
+	if (once_is_more_than_enough)
 		return -ENODEV;
+	once_is_more_than_enough = 1;
 
-	if(++one!=1)	/* Only one is allowed */
+	if (!MACH_IS_MAC)
 		return -ENODEV;
 
 	printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
@@ -198,288 +290,332 @@
 		printk("none.\n");
 		return -ENODEV;
 	}
-	
-	printk("yes\n");
-	
-	if (setup_debug >= 0)
-	  sonic_debug = setup_debug;
-
-	/*
-	 * This may depend on the actual Mac model ... works for me.
-	 */
-	reg_offset = 
-	  (setup_offset >= 0) ? setup_offset : 0;
-	reg_shift = 
-	  (setup_shift >= 0) ? setup_shift : 0;
 
-	/*
-	 * get the Silicon Revision ID. If this is one of the known
-	 * one assume that we found a SONIC ethernet controller at
-	 * the expected location.
-	 * (This is not implemented in the Macintosh driver yet; need
-	 * to collect values from various sources. Mine is 0x4 ...)
-	 */
+	/* Bogus probing, on the models which may or may not have
+	   Ethernet (BTW, the Ethernet *is* always at the same
+	   address, and nothing else lives there, at least if Apple's
+	   documentation is to be believed) */
+	if (macintosh_config->ident == MAC_MODEL_Q630 ||
+	    macintosh_config->ident == MAC_MODEL_P588 ||
+	    macintosh_config->ident == MAC_MODEL_C610) {
+		unsigned long flags;
+		int card_present;
+
+		save_flags(flags);
+		cli();
+		card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS);
+		restore_flags(flags);
+
+		if (!card_present) {
+			printk("none.\n");
+			return -ENODEV;
+		}
+	}
 
-	silicon_revision = SONIC_READ(SONIC_SR);
-	if (sonic_debug > 1)
-		printk("SONIC Silicon Revision = 0x%04x\n", silicon_revision);
+	printk("yes\n");	
+
+	if (dev) {
+		dev = init_etherdev(dev, sizeof(struct sonic_local));
+		/* methinks this will always be true but better safe than sorry */
+		if (dev->priv == NULL)
+			dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL);
+	} else {
+		dev = init_etherdev(NULL, sizeof(struct sonic_local));
+	}
 
-	/*
-	 * We need to allocate sonic_local later on, making sure it's
-	 * aligned on a 64k boundary. So, no space for dev->priv allocated
-	 * here ...
-	 */
-	dev = init_etherdev(0,0);
-	
-	if(dev==NULL)
+	if (dev == NULL)
 		return -ENOMEM;
 
-	printk("%s: %s found at 0x%08x, ",
-	       dev->name, "SONIC ethernet", base_addr);
+	lp = (struct sonic_local*) dev->priv;
+	memset(lp, 0, sizeof(struct sonic_local));
+	/* Danger!  My arms are flailing wildly!  You *must* set this
+           before using sonic_read() */
+
+	dev->base_addr = ONBOARD_SONIC_REGISTERS;
+	if (via_alt_mapping)
+		dev->irq = IRQ_AUTO_3;
+	else
+		dev->irq = IRQ_NUBUS_9;
+
+	if (!sonic_version_printed) {
+		printk(KERN_INFO "%s", version);
+		sonic_version_printed = 1;
+	}
+	printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n",
+	       dev->name, dev->base_addr);
+
+	/* Now do a song and dance routine in an attempt to determine
+           the bus width */
+
+	/* The PowerBook's SONIC is 16 bit always. */
+	if (macintosh_config->ident == MAC_MODEL_PB520) {
+		lp->reg_offset = 0;
+		lp->dma_bitmode = 0;
+	} else {
+		/* Some of the comm-slot cards are 16 bit.  But some
+                   of them are not.  The 32-bit cards use offset 2 and
+                   pad with zeroes or sometimes ones (I think...)
+                   Therefore, if we try offset 0 and get a silicon
+                   revision of 0, we assume 16 bit. */
+		int sr;
+
+		/* Technically this is not necessary since we zeroed
+                   it above */
+		lp->reg_offset = 0;
+		lp->dma_bitmode = 0;
+		sr = sonic_read(dev, SONIC_SR);
+		if (sr == 0 || sr == 0xffff) {
+			lp->reg_offset = 2;
+			/* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */
+			sr = sonic_read(dev, SONIC_SR);
+			lp->dma_bitmode = 1;
+			
+		}
+		printk(KERN_INFO
+		       "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
+		       dev->name, sr, lp->dma_bitmode?32:16, lp->reg_offset);
+	}
+
+
+	/* Software reset, then initialize control registers. */
+	sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
+	sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS |
+		    SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS |
+		    (lp->dma_bitmode ? SONIC_DCR_DW : 0));
+	/* This *must* be written back to in order to restore the
+           extended programmable output bits */
+	sonic_write(dev, SONIC_DCR2, 0);
+
+	/* Clear *and* disable interrupts to be on the safe side */
+	sonic_write(dev, SONIC_ISR,0x7fff);
+	sonic_write(dev, SONIC_IMR,0);
 
-	if (sonic_debug > 1)
-		printk("using offset %d shift %d,", reg_offset, reg_shift);
-
-	/* Fill in the 'dev' fields. */
-	dev->base_addr = base_addr;
-	dev->irq = MAC_SONIC_IRQ;
+	/* Now look for the MAC address. */
+	if (mac_onboard_sonic_ethernet_addr(dev) != 0)
+		return -ENODEV;
 
-	/*
-	 * Put the sonic into software reset, then
-	 * retrieve and print the ethernet address.
-	 */
+	printk(KERN_INFO "MAC ");
+	for (i = 0; i < 6; i++) {
+		printk("%2.2x", dev->dev_addr[i]);
+		if (i < 5)
+			printk(":");
+	}
 
-	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+	printk(" IRQ %d\n", dev->irq);
 
-	/*
-	 *        We can't trust MacOS to initialise things it seems.
-	 */
+	/* Shared init code */
+	return macsonic_init(dev);
+}
 
-	if (sonic_debug > 1)
-		printk("SONIC_DCR was %X\n",SONIC_READ(SONIC_DCR));
-	
-	SONIC_WRITE(SONIC_DCR,
-		    SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | SONIC_DCR_DW);
+int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev,
+					 unsigned long prom_addr,
+					 int id)
+{
+	int i;
+	for(i = 0; i < 6; i++)
+		dev->dev_addr[i] = SONIC_READ_PROM(i);
+	/* For now we are going to assume that they're all bit-reversed */
+	bit_reverse_addr(dev->dev_addr);
 
-	/*
-	 *  We don't want floating spare IRQ's around, not on
-	 *  level triggered systems!
-	 *  Strange though - writing to the ISR only clears currently
-	 *  pending IRQs, but doesn't disable them... Does this make 
-	 *  a difference?? Seems it does ...
-	 */
-#if 1
-	SONIC_WRITE(SONIC_ISR,0x7fff);
-	SONIC_WRITE(SONIC_IMR,0);
-#else
-	SONIC_WRITE(SONIC_ISR, SONIC_IMR_DEFAULT);
-#endif
-	
-	/* This is how it is done in jazzsonic.c
-	 * It doesn't seem to work here though.
-	 */
-	if (sonic_debug > 2) {
-		printk("Retreiving CAM entry 0. This should be the HW address.\n");
-		
-		SONIC_WRITE(SONIC_CEP, 0);
-		for (i = 0; i < 3; i++)
-		{
-			val = SONIC_READ(SONIC_CAP0 - i);
-			dev->dev_addr[i * 2] = val;
-			dev->dev_addr[i * 2 + 1] = val >> 8;
-		}
+	return 0;
+}
 
-		printk("HW Address from CAM 0: ");
-		for (i = 0; i < 6; i++)
-		{
-			printk("%2.2x", dev->dev_addr[i]);
-			if (i < 5)
-				printk(":");
-		}
-		printk("\n");
+int __init macsonic_ident(struct nubus_dev* ndev)
+{
+	if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC && 
+	    ndev->dr_sw == NUBUS_DRSW_SONIC_LC)
+		return MACSONIC_DAYNALINK;
+	if (ndev->dr_hw == NUBUS_DRHW_SONIC &&
+	    ndev->dr_sw == NUBUS_DRSW_APPLE) {
+		/* There has to be a better way to do this... */
+		if (strstr(ndev->board->name, "DuoDock"))
+			return MACSONIC_DUODOCK;
+		else
+			return MACSONIC_APPLE;
+	}
+	return -1;
+}
 
-		printk("Retreiving CAM entry 15. Another candidate...\n");
+int __init mac_nubus_sonic_probe(struct net_device* dev)
+{
+	static int slots = 0;
+	struct nubus_dev* ndev = NULL;
+	struct sonic_local* lp;
+	unsigned long base_addr, prom_addr;
+	u16 sonic_dcr;
+	int id;
+	int i;
+	int reg_offset, dma_bitmode;
 
-		/*
-		 * MacOS seems to use CAM entry 15 ...
-		 */
-	       	SONIC_WRITE(SONIC_CEP, 15);
-		for (i = 0; i < 3; i++)
-		{
-			val = SONIC_READ(SONIC_CAP0 - i);
-			dev->dev_addr[i * 2] = val;
-			dev->dev_addr[i * 2 + 1] = val >> 8;
-		}
+	/* Find the first SONIC that hasn't been initialized already */
+	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
+				       NUBUS_TYPE_ETHERNET, ndev)) != NULL)
+	{
+		/* Have we seen it already? */
+		if (slots & (1<<ndev->board->slot))
+			continue;
+		slots |= 1<<ndev->board->slot;
 
-		printk("HW Address from CAM 15: ");
-		for (i = 0; i < 6; i++)
-		{
-			printk("%2.2x", dev->dev_addr[i]);
-			if (i < 5)
-				printk(":");
-		}
-		printk("\n");
+		/* Is it one of ours? */
+		if ((id = macsonic_ident(ndev)) != -1)
+			break;
 	}
 
-	/*
-	 * if we can read the PROM, we're safe :-)
-	 */
-	if (sonic_debug > 1)
-		printk("Retreiving HW address from the PROM: ");
+	if (ndev == NULL)
+		return -ENODEV;
 
-	for(i=0;i<6;i++){
-                dev->dev_addr[i]=SONIC_READ_PROM(i);
-        }                             
-	if (sonic_debug > 1) {
-	        for (i = 0; i < 6; i++)
-		{
-			printk("%2.2x", dev->dev_addr[i]);
-			if (i <	5)
-				printk(":");
-		}
-		printk("\n");
+	switch (id) {
+	case MACSONIC_DUODOCK:
+		base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS;
+		prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE;
+		sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1
+			| SONIC_DCR_TFT0;
+		reg_offset = 2;
+		dma_bitmode = 1;
+		break;
+	case MACSONIC_APPLE:
+		base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+		prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
+		sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0;
+		reg_offset = 0;
+		dma_bitmode = 1;
+		break;
+	case MACSONIC_APPLE16:
+		base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+		prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
+		sonic_dcr = SONIC_DCR_EXBUS
+ 			| SONIC_DCR_RFT1 | SONIC_DCR_TFT0
+			| SONIC_DCR_PO1 | SONIC_DCR_BMS; 
+		reg_offset = 0;
+		dma_bitmode = 0;
+		break;
+	case MACSONIC_DAYNALINK:
+		base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
+		prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE;
+		sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0
+			| SONIC_DCR_PO1 | SONIC_DCR_BMS; 
+		reg_offset = 0;
+		dma_bitmode = 0;
+		break;
+	case MACSONIC_DAYNA:
+		base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS;
+		prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR;
+		sonic_dcr = SONIC_DCR_BMS
+			| SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1;
+		reg_offset = 0;
+		dma_bitmode = 0;
+		break;
+	default:
+		printk(KERN_ERR "macsonic: WTF, id is %d\n", id);
+		return -ENODEV;
 	}
-	/*
-	 *                If its not one of these we have
-	 *          screwed up on this Mac model
-	 */
 
-	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
-	    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
-	    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
-	{
-		/*
-		 * Try bit reversed
-		 */
-		for(i=0;i<6;i++){
-			val = SONIC_READ_PROM(i);
-			dev->dev_addr[i]=(nibbletab[val & 0xf] << 4) | 
-					  nibbletab[(val >> 4) &0xf];
-		}
-		if (sonic_debug > 1) {
-			printk("Trying bit reversed:  ");
-			for (i = 0; i < 6; i++)
-			{
-				printk("%2.2x", dev->dev_addr[i]);
-				if (i < 5)
-					printk(":");
-			}
-			printk("\n");
-		}
-		if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
-		    memcmp(dev->dev_addr, "\x00\xA0\x40", 3) &&
-		    memcmp(dev->dev_addr, "\x00\x05\x02", 3))
-		{
-		        /*
-			 * Still nonsense ... messed up someplace!
-			 */
-			printk("ERROR (INVALID MAC)\n");
-			return -EIO;
-		}
+	if (dev) {
+		dev = init_etherdev(dev, sizeof(struct sonic_local));
+		/* methinks this will always be true but better safe than sorry */
+		if (dev->priv == NULL)
+			dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL);
+	} else {
+		dev = init_etherdev(NULL, sizeof(struct sonic_local));
 	}
 
-	printk(" MAC ");
-	for (i = 0; i < 6; i++)
-	{
+	if (dev == NULL)
+		return -ENOMEM;
+
+	lp = (struct sonic_local*) dev->priv;
+	memset(lp, 0, sizeof(struct sonic_local));
+	/* Danger!  My arms are flailing wildly!  You *must* set this
+           before using sonic_read() */
+	lp->reg_offset = reg_offset;
+	lp->dma_bitmode = dma_bitmode;
+	dev->base_addr = base_addr;
+	dev->irq = SLOT2IRQ(ndev->board->slot);
+
+	if (!sonic_version_printed) {
+		printk(KERN_INFO "%s", version);
+		sonic_version_printed = 1;
+	}
+	printk(KERN_INFO "%s: %s in slot %X\n",
+	       dev->name, ndev->board->name, ndev->board->slot);
+	printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n",
+	       dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset);
+
+	/* Software reset, then initialize control registers. */
+	sonic_write(dev, SONIC_CMD, SONIC_CR_RST);
+	sonic_write(dev, SONIC_DCR, sonic_dcr
+		    | (dma_bitmode ? SONIC_DCR_DW : 0));
+
+	/* Clear *and* disable interrupts to be on the safe side */
+	sonic_write(dev, SONIC_ISR,0x7fff);
+	sonic_write(dev, SONIC_IMR,0);
+
+	/* Now look for the MAC address. */
+	if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0)
+		return -ENODEV;
+
+	printk(KERN_INFO "MAC ");
+	for (i = 0; i < 6; i++) {
 		printk("%2.2x", dev->dev_addr[i]);
 		if (i < 5)
 			printk(":");
 	}
+	printk(" IRQ %d\n", dev->irq);
 
-	printk(" IRQ %d\n", MAC_SONIC_IRQ);
+	/* Shared init code */
+	return macsonic_init(dev);
+}
 
-	/* Initialize the device structure. */
-	if (dev->priv == NULL)
-	{
-		if (sonic_debug > 2) {
-			printk("Allocating memory for dev->priv aka lp\n");
-			printk("Memory to allocate: %d\n",sizeof(*lp));
-		}
-		/*
-		 * the memory be located in the same 64kb segment
-		 */
-		lp = NULL;
-		i = 0;
-		do
-		{
-			lp = (struct sonic_local *) kmalloc(sizeof(*lp), GFP_KERNEL);
-			if ((unsigned long) lp >> 16 != ((unsigned long) lp + sizeof(*lp)) >> 16)
-			{
-				/* FIXME, free the memory later */
-				kfree(lp);
-				lp = NULL;
-			}
-		}
-		while (lp == NULL && i++ < 20);
+#ifdef MODULE
+static char namespace[16] = "";
+static struct net_device dev_macsonic = {
+        NULL,
+        0, 0, 0, 0,
+        0, 0,
+        0, 0, 0, NULL, NULL };
 
-		if (lp == NULL)
-		{
-			printk("%s: couldn't allocate memory for descriptors\n",
-			       dev->name);
-			return -ENOMEM;
-		}
+MODULE_PARM(sonic_debug, "i");
 
-		if (sonic_debug > 2) {
-			printk("Memory allocated after %d tries\n",i);
-		}
+EXPORT_NO_SYMBOLS;
 
-		/* XXX sonic_local has the TDA, RRA, RDA, don't cache */
-		kernel_set_cachemode((u32)lp, 8192, IOMAP_NOCACHE_SER);
-		memset(lp, 0, sizeof(struct sonic_local));
-
-		lp->cda_laddr = (u32)lp;
-		if (sonic_debug > 2) {
-			printk("memory allocated for sonic at 0x%x\n",lp);
-		}
-		lp->tda_laddr = lp->cda_laddr + sizeof(lp->cda);
-		lp->rra_laddr = lp->tda_laddr + sizeof(lp->tda);
-		lp->rda_laddr = lp->rra_laddr + sizeof(lp->rra);
-
-		/* allocate receive buffer area */
-		/* FIXME, maybe we should use skbs */
-		if ((lp->rba = (char *) kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL)
-		{
-			printk("%s: couldn't allocate receive buffers\n", dev->name);
-			return -ENOMEM;
-		}
-		/* XXX RBA written by Sonic, not cached either */
-		kernel_set_cachemode((u32)lp->rba, 6*8192, IOMAP_NOCACHE_SER);
-		lp->rba_laddr = (u32)lp->rba;
-		flush_cache_all();
-		dev->priv = (struct sonic_local *) lp;
-	}
-	lp = (struct sonic_local *) dev->priv;
-	dev->open = sonic_open;
-	dev->stop = sonic_close;
-	dev->hard_start_xmit = sonic_send_packet;
-	dev->get_stats = sonic_get_stats;
-	dev->set_multicast_list = &sonic_multicast_list;
+int
+init_module(void)
+{
+        dev_macsonic.name = namespace;
+        dev_macsonic.init = macsonic_probe;
 
-	/* Fill in the fields of the device structure with ethernet values. */
-	ether_setup(dev);
+        if (register_netdev(&dev_macsonic) != 0) {
+                printk(KERN_WARNING "macsonic.c: No card found\n");
+                return -ENXIO;
+        }
 	return 0;
 }
 
-/*
- *    SONIC uses a nubus IRQ
- */
+void
+cleanup_module(void)
+{
+        if (dev_macsonic.priv != NULL) {
+                unregister_netdev(&dev_macsonic);
+                kfree(dev_macsonic.priv);
+                dev_macsonic.priv = NULL;
+        }
+}
+#endif /* MODULE */
 
-#define sonic_request_irq(irq, vec, flags, name, dev) \
-		nubus_request_irq(irq, dev, vec)
-#define sonic_free_irq(irq,id)	nubus_free_irq(irq)
 
-/*
- *    No funnies on memory mapping.
- */
+#define vdma_alloc(foo, bar) ((u32)foo)
+#define vdma_free(baz)
+#define sonic_chiptomem(bat) (bat)
+#define PHYSADDR(quux) (quux)
 
-#define sonic_chiptomem(x)	(x)
+#include "sonic.c"
 
 /*
- *    No VDMA on a Macintosh. So we need request no such facility.
+ * Local variables:
+ *  compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o macsonic.o macsonic.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  c-indent-level: 8
+ *  tab-width: 8
+ * End:
+ *
  */
-
-#define vdma_alloc(x,y)		((u32)(x))
-#define vdma_free(x)
-#define PHYSADDR(x)		(x)
-
-#include "sonic.c"
diff -u --recursive --new-file v2.3.41/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.3.41/linux/drivers/net/sun3lance.c	Fri Sep 10 23:57:30 1999
+++ linux/drivers/net/sun3lance.c	Mon Jan 31 10:30:00 2000
@@ -21,7 +21,7 @@
   
 */
 
-static char *version = "sun3lance.c: v1.0 12/12/96  Sam Creasey (sammy@users.qual.net)\n";
+static char *version = "sun3lance.c: v1.1 11/17/1999  Sam Creasey (sammy@oh.verio.com)\n";
 
 #include <linux/module.h>
 
@@ -263,6 +263,8 @@
 	int 			i;
 	static int 		did_version = 0;
 	int found = 0;
+	volatile unsigned short *ioaddr_probe;
+	unsigned short tmp1, tmp2;
 
 	/* LANCE_OBIO can be found within the IO pmeg with some effort */
 	for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
@@ -281,6 +283,23 @@
 	
 	if(!found)
 		return 0;
+
+	/* test to see if there's really a lance here */
+	/* (CSRO_INIT shouldn't be readable) */
+	
+	ioaddr_probe = (volatile unsigned short *)ioaddr;
+	tmp1 = ioaddr_probe[0];
+	tmp2 = ioaddr_probe[1];
+
+	ioaddr_probe[1] = CSR0;
+	ioaddr_probe[0] = CSR0_INIT | CSR0_STOP;
+
+	if(ioaddr_probe[0] != CSR0_STOP) {
+		ioaddr_probe[0] = tmp1;
+		ioaddr_probe[1] = tmp2;
+
+		return 0;
+	}
 
 	init_etherdev( dev, sizeof(struct lance_private) );
 	if (!dev->priv)
diff -u --recursive --new-file v2.3.41/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c
--- v2.3.41/linux/drivers/net/sunbmac.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/sunbmac.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sunbmac.c,v 1.12 1999/12/15 14:07:58 davem Exp $
+/* $Id: sunbmac.c,v 1.13 2000/01/28 13:42:29 jj Exp $
  * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
diff -u --recursive --new-file v2.3.41/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.3.41/linux/drivers/net/sunhme.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/sunhme.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.84 1999/12/15 14:08:03 davem Exp $
+/* $Id: sunhme.c,v 1.85 2000/01/28 13:42:27 jj Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
diff -u --recursive --new-file v2.3.41/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.3.41/linux/drivers/net/sunlance.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/sunlance.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sunlance.c,v 1.92 1999/12/15 14:08:09 davem Exp $
+/* $Id: sunlance.c,v 1.93 2000/01/28 13:42:31 jj Exp $
  * lance.c: Linux/Sparc/Lance driver
  *
  *	Written 1995, 1996 by Miguel de Icaza
diff -u --recursive --new-file v2.3.41/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.3.41/linux/drivers/net/sunqe.c	Fri Jan 28 15:09:07 2000
+++ linux/drivers/net/sunqe.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.40 1999/12/15 14:08:13 davem Exp $
+/* $Id: sunqe.c,v 1.41 2000/01/28 13:42:30 jj Exp $
  * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
  *          Once again I am out to prove that every ethernet
  *          controller out there can be most efficiently programmed
diff -u --recursive --new-file v2.3.41/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.3.41/linux/drivers/sbus/audio/cs4231.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/sbus/audio/cs4231.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: cs4231.c,v 1.41 1999/12/19 23:28:03 davem Exp $
+/* $Id: cs4231.c,v 1.42 2000/01/28 13:42:48 jj Exp $
  * drivers/sbus/audio/cs4231.c
  *
  * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
diff -u --recursive --new-file v2.3.41/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c
--- v2.3.41/linux/drivers/sbus/audio/dbri.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/sbus/audio/dbri.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.17 2000/01/20 07:57:47 anton Exp $
+/* $Id: dbri.c,v 1.18 2000/01/28 13:42:50 jj Exp $
  * drivers/sbus/audio/dbri.c
  *
  * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
diff -u --recursive --new-file v2.3.41/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- v2.3.41/linux/drivers/sbus/char/zs.c	Wed Dec 29 13:13:18 1999
+++ linux/drivers/sbus/char/zs.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.52 1999/12/15 14:29:20 davem Exp $
+/* $Id: zs.c,v 1.53 2000/01/29 01:29:38 anton Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1928,7 +1928,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.52 $";
+	char *revision = "$Revision: 1.53 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2076,11 +2076,6 @@
 	static int irq = 0;
 	int chipid = chip;
 
-#if CONFIG_AP1000
-        printk("No zs chip\n");
-        return NULL;
-#endif
-
 	iospace = 0;
 	if(chip < 0 || chip >= NUM_SERIAL)
 		panic("get_zs bogon zs chip number");
@@ -2406,11 +2401,6 @@
 	unsigned long flags;
 	struct sun_serial *info;
 	char dummy;
-
-#if CONFIG_AP1000
-        printk("not doing zs_init()\n");
-        return 0;
-#endif
 
 	/* Setup base handler, and timer table. */
 	init_bh(SERIAL_BH, do_serial_bh);
diff -u --recursive --new-file v2.3.41/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.3.41/linux/drivers/scsi/esp.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/esp.c	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: esp.c,v 1.89 1999/12/23 01:46:14 davem Exp $
+/* $Id: esp.c,v 1.90 2000/01/28 13:42:56 jj Exp $
  * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
  *
  * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/drivers/scsi/scsi_merge.c linux/drivers/scsi/scsi_merge.c
--- v2.3.41/linux/drivers/scsi/scsi_merge.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/scsi_merge.c	Tue Feb  1 01:31:04 2000
@@ -87,7 +87,7 @@
 	 * Dump the information that we have.  We know we have an
 	 * inconsistency.
 	 */
-	printk("nr_segments is %lx\n", req->nr_segments);
+	printk("nr_segments is %x\n", req->nr_segments);
 	printk("counted segments is %x\n", segments);
 	printk("Flags %d %d\n", use_clustering, dma_host);
 	for (bh = req->bh; bh->b_reqnext != NULL; bh = bh->b_reqnext) 
diff -u --recursive --new-file v2.3.41/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.41/linux/drivers/scsi/sd.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/scsi/sd.c	Sat Jan 29 00:17:38 2000
@@ -373,6 +373,7 @@
 static int sd_open(struct inode *inode, struct file *filp)
 {
 	int target;
+	Scsi_Device * SDev;
 	target = DEVICE_NR(inode->i_rdev);
 
 	SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max));
@@ -412,13 +413,14 @@
 		if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2))
 			return -EROFS;
 	}
+	SDev = rscsi_disks[target].device;
 	/*
 	 * It is possible that the disk changing stuff resulted in the device
 	 * being taken offline.  If this is the case, report this to the user,
 	 * and don't pretend that
 	 * the open actually succeeded.
 	 */
-	if (!rscsi_disks[target].device->online) {
+	if (!SDev->online) {
 		return -ENXIO;
 	}
 	/*
@@ -428,13 +430,14 @@
 	if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
 		return -ENXIO;
 
-	if (rscsi_disks[target].device->removable)
-		if (!rscsi_disks[target].device->access_count)
-			sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
-
-	rscsi_disks[target].device->access_count++;
-	if (rscsi_disks[target].device->host->hostt->module)
-		__MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+	if (SDev->removable)
+		if (!SDev->access_count)
+			if (scsi_block_when_processing_errors(SDev))
+				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
+
+	SDev->access_count++;
+	if (SDev->host->hostt->module)
+		__MOD_INC_USE_COUNT(SDev->host->hostt->module);
 	if (sd_template.module)
 		__MOD_INC_USE_COUNT(sd_template.module);
 	return 0;
@@ -443,17 +446,20 @@
 static int sd_release(struct inode *inode, struct file *file)
 {
 	int target;
+	Scsi_Device * SDev;
 
 	target = DEVICE_NR(inode->i_rdev);
+	SDev = rscsi_disks[target].device;
 
-	rscsi_disks[target].device->access_count--;
+	SDev->access_count--;
 
-	if (rscsi_disks[target].device->removable) {
-		if (!rscsi_disks[target].device->access_count)
-			sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+	if (SDev->removable) {
+		if (!SDev->access_count)
+			if (scsi_block_when_processing_errors(SDev))
+				scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL);
 	}
-	if (rscsi_disks[target].device->host->hostt->module)
-		__MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+	if (SDev->host->hostt->module)
+		__MOD_DEC_USE_COUNT(SDev->host->hostt->module);
 	if (sd_template.module)
 		__MOD_DEC_USE_COUNT(sd_template.module);
 	return 0;
@@ -580,17 +586,17 @@
 {
 	int retval;
 	int target;
-	struct inode inode;
 	int flag = 0;
+	Scsi_Device * SDev;
 
 	target = DEVICE_NR(full_dev);
+	SDev = rscsi_disks[target].device;
 
-	if (target >= sd_template.dev_max ||
-	    !rscsi_disks[target].device) {
+	if (target >= sd_template.dev_max || !SDev) {
 		printk("SCSI disk request error: invalid device.\n");
 		return 0;
 	}
-	if (!rscsi_disks[target].device->removable)
+	if (!SDev->removable)
 		return 0;
 
 	/*
@@ -599,13 +605,12 @@
 	 * can deal with it then.  It is only because of unrecoverable errors
 	 * that we would ever take a device offline in the first place.
 	 */
-	if (rscsi_disks[target].device->online == FALSE) {
+	if (SDev->online == FALSE) {
 		rscsi_disks[target].ready = 0;
-		rscsi_disks[target].device->changed = 1;
+		SDev->changed = 1;
 		return 1;	/* This will force a flush, if called from
 				 * check_disk_change */
 	}
-	inode.i_rdev = full_dev;	/* This is all we really need here */
 
 	/* Using Start/Stop enables differentiation between drive with
 	 * no cartridge loaded - NOT READY, drive with changed cartridge -
@@ -613,7 +618,9 @@
 	 * This also handles drives that auto spin down. eg iomega jaz 1GB
 	 * as this will spin up the drive.
 	 */
-	retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0);
+	retval = -ENODEV;
+	if (scsi_block_when_processing_errors(SDev))
+		retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL);
 
 	if (retval) {		/* Unable to test, unit probably not ready.
 				 * This usually means there is no disc in the
@@ -622,7 +629,7 @@
 				 * again.  */
 
 		rscsi_disks[target].ready = 0;
-		rscsi_disks[target].device->changed = 1;
+		SDev->changed = 1;
 		return 1;	/* This will force a flush, if called from
 				 * check_disk_change */
 	}
@@ -634,9 +641,9 @@
 
 	rscsi_disks[target].ready = 1;	/* FLOPTICAL */
 
-	retval = rscsi_disks[target].device->changed;
+	retval = SDev->changed;
 	if (!flag)
-		rscsi_disks[target].device->changed = 0;
+		SDev->changed = 0;
 	return retval;
 }
 
diff -u --recursive --new-file v2.3.41/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.3.41/linux/drivers/sound/Config.in	Wed Dec 29 13:13:19 1999
+++ linux/drivers/sound/Config.in	Fri Jan 28 19:36:23 2000
@@ -26,7 +26,7 @@
     dep_tristate '  SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
 fi
 
-dep_tristate '  Trident 4DWave-DX/NX' CONFIG_SOUND_TRIDENT $CONFIG_SOUND
+dep_tristate '  Trident 4DWave DX/NX or SiS 7018 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND
 
 dep_tristate '  Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
 if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
diff -u --recursive --new-file v2.3.41/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.3.41/linux/drivers/sound/Makefile	Fri Jan  7 19:13:22 2000
+++ linux/drivers/sound/Makefile	Fri Jan 28 19:36:23 2000
@@ -25,7 +25,7 @@
 export-objs	:=  ad1848.o audio_syms.o midi_syms.o mpu401.o \
 		    msnd.o opl3.o sb_card.o sequencer_syms.o \
 		    sound_core.o sound_syms.o uart401.o ad1816.o \
-		    nm256_audio.o ac97.o
+		    nm256_audio.o ac97.o ac97_codec.o
 
 
 
@@ -84,7 +84,7 @@
 obj-$(CONFIG_SOUND_ES1371)	+= es1371.o
 obj-$(CONFIG_SOUND_ESSSOLO1)	+= esssolo1.o
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
-obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o
+obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
 
 # Declare multi-part drivers.
 
diff -u --recursive --new-file v2.3.41/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
--- v2.3.41/linux/drivers/sound/ac97_codec.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/ac97_codec.c	Mon Jan 31 23:43:51 2000
@@ -0,0 +1,440 @@
+/*
+ * ac97_codec.c: Generic AC97 mixer module
+ *
+ * Derived from ac97 mixer in maestro and trident driver.
+ *
+ * Copyright 2000 Silicon Integrated System Corporation
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  History
+ *	Jan 14 2000 Ollie Lho <ollie@sis.com.tw> 
+ *	Isloated from trident.c to support multiple ac97 codec
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+
+#include "ac97_codec.h"
+
+static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel);
+static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel, 
+			     unsigned int left, unsigned int right);
+static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val );
+static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask);
+static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
+
+static struct {
+	unsigned int id;
+	char *name;
+	int  (*init)  (struct ac97_codec *codec);
+} snd_ac97_codec_ids[] = {
+	{0x414B4D00, "Asahi Kasei AK4540"     , NULL},
+	{0x41445340, "Analog Devices AD1881"  , NULL},
+	{0x43525900, "Cirrus Logic CS4297"    , NULL},
+	{0x43525913, "Cirrus Logic CS4297A"   , NULL},
+	{0x43525931, "Cirrus Logic CS4299"    , NULL},
+	{0x4e534331, "National Semiconductor LM4549", NULL},
+	{0x83847600, "SigmaTel STAC????"      , NULL},
+	{0x83847604, "SigmaTel STAC9701/3/4/5", NULL},
+	{0x83847605, "SigmaTel STAC9704"      , NULL},
+	{0x83847608, "SigmaTel STAC9708"      , NULL},
+	{0x83847609, "SigmaTel STAC9721/23"   , NULL},
+	{0x00000000, NULL, NULL}
+};
+
+
+/* this table has default mixer values for all OSS mixers. */
+static struct mixer_defaults {
+	int mixer;
+	unsigned int value;
+} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
+	/* all values 0 -> 100 in bytes */
+	{SOUND_MIXER_VOLUME,	0x3232},
+	{SOUND_MIXER_BASS,	0x3232},
+	{SOUND_MIXER_TREBLE,	0x3232},
+	{SOUND_MIXER_PCM,	0x3232},
+	{SOUND_MIXER_SPEAKER,	0x3232},
+	{SOUND_MIXER_LINE,	0x3232},
+	{SOUND_MIXER_MIC,	0x3232},
+	{SOUND_MIXER_CD,	0x3232},
+	{SOUND_MIXER_ALTPCM,	0x3232},
+	{SOUND_MIXER_IGAIN,	0x3232},
+	{SOUND_MIXER_LINE1,	0x3232},
+	{SOUND_MIXER_PHONEIN,	0x3232},
+	{SOUND_MIXER_PHONEOUT,	0x3232},
+	{SOUND_MIXER_VIDEO,	0x3232},
+	{-1,0}
+};
+
+/* table to scale scale from OSS mixer value to AC97 mixer register value */	
+static struct ac97_mixer_hw {
+	unsigned char offset;
+	int scale;
+} ac97_hw[SOUND_MIXER_NRDEVICES]= {
+	[SOUND_MIXER_VOLUME]	=	{AC97_MASTER_VOL_STEREO,63},
+	[SOUND_MIXER_BASS]	=	{AC97_MASTER_TONE,	15},
+	[SOUND_MIXER_TREBLE]	=	{AC97_MASTER_TONE, 	15},
+	[SOUND_MIXER_PCM]	=	{AC97_PCMOUT_VOL,	31},
+	[SOUND_MIXER_SPEAKER]	=	{AC97_PCBEEP_VOL,  	15},
+	[SOUND_MIXER_LINE]	=	{AC97_LINEIN_VOL,	31},
+	[SOUND_MIXER_MIC]	=	{AC97_MIC_VOL,		31},
+	[SOUND_MIXER_CD]	=	{AC97_CD_VOL,		31},
+	[SOUND_MIXER_ALTPCM]	=	{AC97_HEADPHONE_VOL,	63},
+	[SOUND_MIXER_IGAIN]	=	{AC97_RECORD_GAIN,	31},
+	[SOUND_MIXER_LINE1]	=	{AC97_AUX_VOL,		31},
+	[SOUND_MIXER_PHONEIN]	= 	{AC97_PHONE_VOL,	15},
+	[SOUND_MIXER_PHONEOUT]	= 	{AC97_MASTER_VOL_MONO,	63},
+	[SOUND_MIXER_VIDEO]	=	{AC97_VIDEO_VOL,	31},
+};
+
+/* the following tables allow us to go from OSS <-> ac97 quickly. */
+enum ac97_recsettings {
+	AC97_REC_MIC=0,
+	AC97_REC_CD,
+	AC97_REC_VIDEO,
+	AC97_REC_AUX,
+	AC97_REC_LINE,
+	AC97_REC_STEREO, /* combination of all enabled outputs..  */
+	AC97_REC_MONO,	      /*.. or the mono equivalent */
+	AC97_REC_PHONE	      
+};
+
+static unsigned int ac97_rm2oss[] = {
+	[AC97_REC_MIC] 	 = SOUND_MIXER_MIC, 
+	[AC97_REC_CD] 	 = SOUND_MIXER_CD, 
+	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, 
+	[AC97_REC_AUX] 	 = SOUND_MIXER_LINE1, 
+	[AC97_REC_LINE]  = SOUND_MIXER_LINE, 
+	[AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
+};
+
+/* indexed by bit position */
+static unsigned int ac97_oss_rm[] = {
+	[SOUND_MIXER_MIC] 	= AC97_REC_MIC,
+	[SOUND_MIXER_CD] 	= AC97_REC_CD,
+	[SOUND_MIXER_VIDEO] 	= AC97_REC_VIDEO,
+	[SOUND_MIXER_LINE1] 	= AC97_REC_AUX,
+	[SOUND_MIXER_LINE] 	= AC97_REC_LINE,
+	[SOUND_MIXER_PHONEIN] 	= AC97_REC_PHONE
+};
+
+/* reads the given OSS mixer from the ac97 the caller must have insured that the ac97 knows
+   about that given mixer, and should be holding a spinlock for the card */
+static int ac97_read_mixer(struct ac97_codec *codec, int oss_channel) 
+{
+	u16 val;
+	int ret = 0;
+	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
+
+	val = codec->codec_read(codec , mh->offset);
+
+	if (AC97_STEREO_MASK & (1 << oss_channel)) {
+		/* nice stereo mixers .. */
+		int left,right;
+
+		left = (val >> 8)  & 0x7f;
+		right = val  & 0x7f;
+
+		if (oss_channel == SOUND_MIXER_IGAIN) {
+			right = (right * 100) / mh->scale;
+			left = (left * 100) / mh->scale;
+		} else {
+			right = 100 - ((right * 100) / mh->scale);
+			left = 100 - ((left * 100) / mh->scale);
+		}
+
+		ret = left | (right << 8);
+	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
+		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
+	} else if (oss_channel == SOUND_MIXER_MIC) {
+		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+		/*  the low bit is optional in the tone sliders and masking
+		    it lets us avoid the 0xf 'bypass'.. */
+	} else if (oss_channel == SOUND_MIXER_BASS) {
+		ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
+	} else if (oss_channel == SOUND_MIXER_TREBLE) {
+		ret = 100 - (((val & 0xe) * 100) / mh->scale);
+	}
+
+#ifdef DEBUG
+	printk("ac97_codec: read OSS mixer %2d (ac97 register 0x%02x), "
+	       "0x%04x -> 0x%04x\n", oss_channel, mh->offset, val, ret);
+#endif
+
+	return ret;
+}
+
+/* write the OSS encoded volume to the given OSS encoded mixer, again caller's job to
+   make sure all is well in arg land, call with spinlock held */
+static void ac97_write_mixer(struct ac97_codec *codec, int oss_channel,
+		      unsigned int left, unsigned int right)
+{
+	u16 val = 0;
+	struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
+
+#ifdef DEBUG
+	printk("ac97_codec: wrote OSS mixer %2d (%s ac97 register 0x%02x), "
+	       "left vol:%2d, right vol:%2d:",
+	       oss_channel, codec->id ? "Secondary" : "Primary",
+	       mh->offset, left, right);
+#endif
+
+	if (AC97_STEREO_MASK & (1 << oss_channel)) {
+		/* stereo mixers */
+		if (oss_channel == SOUND_MIXER_IGAIN) {
+			right = (right * mh->scale) / 100;
+			left = (left * mh->scale) / 100;
+		} else {
+			right = ((100 - right) * mh->scale) / 100;
+			left = ((100 - left) * mh->scale) / 100;
+		}
+		val = (left << 8) | right;
+	} else if (oss_channel == SOUND_MIXER_SPEAKER) {
+		val = (((100 - left) * mh->scale) / 100) << 1;
+	} else if (oss_channel == SOUND_MIXER_MIC) {
+		val = codec->codec_read(codec , mh->offset) & ~0x801f;
+		val |= (((100 - left) * mh->scale) / 100);
+		/*  the low bit is optional in the tone sliders and masking
+		    it lets us avoid the 0xf 'bypass'.. */
+	} else if (oss_channel == SOUND_MIXER_BASS) {
+		val = codec->codec_read(codec , mh->offset) & ~0x0f00;
+		val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
+	} else if (oss_channel == SOUND_MIXER_TREBLE)	 {
+		val = codec->codec_read(codec , mh->offset) & ~0x000f;
+		val |= (((100 - left) * mh->scale) / 100) & 0x000e;
+	}
+
+#ifdef DEBUG
+	printk(" 0x%04x", val);
+#endif
+	codec->codec_write(codec, mh->offset, val);
+
+#ifdef DEBUG
+	val = codec->codec_read(codec, mh->offset);
+	printk(" -> 0x%04x\n", val);
+#endif
+}
+
+/* a thin wrapper for write_mixer */
+static void ac97_set_mixer(struct ac97_codec *codec, unsigned int oss_mixer, unsigned int val ) 
+{
+	unsigned int left,right;
+
+	/* cleanse input a little */
+	right = ((val >> 8)  & 0xff) ;
+	left = (val  & 0xff) ;
+
+	if (right > 100) right = 100;
+	if (left > 100) left = 100;
+
+	codec->mixer_state[oss_mixer] = (right << 8) | left;
+	codec->write_mixer(codec, oss_mixer, left, right);
+}
+
+/* read or write the recmask, the ac97 can really have left and right recording
+   inputs independantly set, but OSS doesn't seem to want us to express that to
+   the user. the caller guarantees that we have a supported bit set, and they
+   must be holding the card's spinlock */
+static int ac97_recmask_io(struct ac97_codec *codec, int rw, int mask) 
+{
+	unsigned int val;
+
+	if (rw) {
+		/* read it from the card */
+		val = codec->codec_read(codec, 0x1a) & 0x7;
+		return ac97_rm2oss[val];
+	}
+
+	/* else, write the first set in the mask as the
+	   output */	
+
+	val = ffs(mask); 
+	val = ac97_oss_rm[val-1];
+	val |= val << 8;  /* set both channels */
+
+#ifdef DEBUG
+	printk("ac97_codec: setting ac97 recmask to 0x%x\n", val);
+#endif
+
+	codec->codec_write(codec, 0x1a, val);
+
+	return 0;
+};
+
+static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned long arg)
+{
+	int i, val = 0;
+
+	if (cmd == SOUND_MIXER_INFO) {
+		mixer_info info;
+		strncpy(info.id, codec->name, sizeof(info.id));
+		strncpy(info.name, codec->name, sizeof(info.name));
+		info.modify_counter = codec->modcnt;
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == SOUND_OLD_MIXER_INFO) {
+		_old_mixer_info info;
+		strncpy(info.id, codec->name, sizeof(info.id));
+		strncpy(info.name, codec->name, sizeof(info.name));
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+		return -EINVAL;
+
+	if (cmd == OSS_GETVERSION)
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	if (_IOC_DIR(cmd) == _IOC_READ) {
+		switch (_IOC_NR(cmd)) {
+		case SOUND_MIXER_RECSRC: /* give them the current record source */
+			if (!codec->recmask_io) {
+				val = 0;
+			} else {
+				val = codec->recmask_io(codec, 1, 0);
+			}
+			break;
+
+		case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
+			val = codec->supported_mixers;
+			break;
+
+		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+			val = codec->record_sources;
+			break;
+
+		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+			val = codec->stereo_mixers;
+			break;
+
+		case SOUND_MIXER_CAPS:
+			val = SOUND_CAP_EXCL_INPUT;
+			break;
+
+		default: /* read a specific mixer */
+			i = _IOC_NR(cmd);
+
+			if (!supported_mixer(codec, i)) 
+				return -EINVAL;
+
+			/* do we ever want to touch the hardware? */
+			/* val = codec->read_mixer(card,i); */
+			val = codec->mixer_state[i];
+			break;
+		}
+		return put_user(val,(int *)arg);
+	}
+
+	if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
+		codec->modcnt++;
+		get_user_ret(val, (int *)arg, -EFAULT);
+
+		switch (_IOC_NR(cmd)) {
+		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+			if (!codec->recmask_io) return -EINVAL;
+			if (!(val &= codec->record_sources)) return -EINVAL;
+
+			codec->recmask_io(codec, 0, val);
+
+			return 0;
+		default: /* write a specific mixer */
+			i = _IOC_NR(cmd);
+
+			if (!supported_mixer(codec, i)) 
+				return -EINVAL;
+
+			ac97_set_mixer(codec, i, val);
+
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+int ac97_probe_codec(struct ac97_codec *codec)
+{
+	u16 id1, id2, cap;
+	int i;
+
+	/* probing AC97 codec, AC97 2.0 says that bit 15 of register 0x00 (reset) should 
+	   be read zero. Probing of AC97 in this way is not reliable, it is not even SAFE !! */
+	codec->codec_write(codec, AC97_RESET, 0L);
+	if ((cap = codec->codec_read(codec, AC97_RESET)) & 0x8000)
+		return 0;
+	
+	id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
+	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+	for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
+		if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+			codec->name = snd_ac97_codec_ids[i].name;
+			codec->codec_init = snd_ac97_codec_ids[i].init;
+			break;
+		}
+	}
+	if (codec->name == NULL)
+		codec->name = "Unknown";
+	printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
+	       id1, id2, codec->name);
+	printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap);
+
+	/* mixer masks */
+	codec->supported_mixers = AC97_SUPPORTED_MASK;
+	codec->stereo_mixers = AC97_STEREO_MASK;
+	codec->record_sources = AC97_RECORD_MASK;
+	if (!(cap & 0x04))
+		codec->supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
+
+	/* generic OSS to AC97 wrapper */
+	codec->read_mixer = ac97_read_mixer;
+	codec->write_mixer = ac97_write_mixer;
+	codec->recmask_io = ac97_recmask_io;
+	codec->mixer_ioctl = ac97_mixer_ioctl;
+
+	/* initialize volume level */
+	codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0L);
+	codec->codec_write(codec, AC97_PCMOUT_VOL, 0L);
+
+	/* codec specific initialization for 4-6 channel output */
+	if (codec->id != 0 && codec->codec_init != NULL) {
+		codec->codec_init(codec);
+	}
+
+	/* initilize mixer channel volumes */
+	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
+		struct mixer_defaults *md = &mixer_defaults[i];
+		if (md->mixer == -1) 
+			break;
+		if (!supported_mixer(codec, md->mixer)) 
+			continue;
+		ac97_set_mixer(codec, md->mixer, md->value);
+	}
+
+	return 1;
+}
+
+static int sigmatel_init(struct ac97_codec * codec)
+{
+	codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
+	/* initialize SigmaTel STAC9721/23 */
+	codec->codec_write(codec, 0x74, 0x01);
+	return 1;
+}
+
+EXPORT_SYMBOL(ac97_probe_codec);
diff -u --recursive --new-file v2.3.41/linux/drivers/sound/ac97_codec.h linux/drivers/sound/ac97_codec.h
--- v2.3.41/linux/drivers/sound/ac97_codec.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/ac97_codec.h	Fri Jan 28 19:36:23 2000
@@ -0,0 +1,157 @@
+#ifndef _AC97_CODEC_H_
+#define _AC97_CODEC_H_
+
+#include "sound_config.h"
+#include "sound_calls.h"
+
+/* AC97 1.0 */
+#define  AC97_RESET               0x0000      //
+#define  AC97_MASTER_VOL_STEREO   0x0002      // Line Out
+#define  AC97_HEADPHONE_VOL       0x0004      // 
+#define  AC97_MASTER_VOL_MONO     0x0006      // TAD Output
+#define  AC97_MASTER_TONE         0x0008      //
+#define  AC97_PCBEEP_VOL          0x000a      // none
+#define  AC97_PHONE_VOL           0x000c      // TAD Input (mono)
+#define  AC97_MIC_VOL             0x000e      // MIC Input (mono)
+#define  AC97_LINEIN_VOL          0x0010      // Line Input (stereo)
+#define  AC97_CD_VOL              0x0012      // CD Input (stereo)
+#define  AC97_VIDEO_VOL           0x0014      // none
+#define  AC97_AUX_VOL             0x0016      // Aux Input (stereo)
+#define  AC97_PCMOUT_VOL          0x0018      // Wave Output (stereo)
+#define  AC97_RECORD_SELECT       0x001a      //
+#define  AC97_RECORD_GAIN         0x001c
+#define  AC97_RECORD_GAIN_MIC     0x001e
+#define  AC97_GENERAL_PURPOSE     0x0020
+#define  AC97_3D_CONTROL          0x0022
+#define  AC97_MODEM_RATE          0x0024
+#define  AC97_POWER_CONTROL       0x0026
+
+/* AC'97 2.0 */
+#define AC97_EXTENDED_ID          0x0028       /* Extended Audio ID */
+#define AC97_EXTENDED_STATUS      0x002A       /* Extended Audio Status */
+#define AC97_PCM_FRONT_DAC_RATE   0x002C       /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE    0x002E       /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE     0x0030       /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_DAC_RATE      0x0032       /* PCM LR DAC Rate */
+#define AC97_PCM_MIC_ADC_RATE     0x0034       /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER    0x0036       /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER      0x0038       /* Surround (Rear) Master Volume */
+#define AC97_RESERVED_3A          0x003A       /* Reserved */
+
+/* range 0x3c-0x58 - MODEM */
+
+/* registers 0x005a - 0x007a are vendor reserved */
+
+#define AC97_VENDOR_ID1           0x007c
+#define AC97_VENDOR_ID2           0x007e
+
+/* volume control bit defines */
+#define AC97_MUTE                 0x8000
+#define AC97_MICBOOST             0x0040
+#define AC97_LEFTVOL              0x3f00
+#define AC97_RIGHTVOL             0x003f
+
+/* record mux defines */
+#define AC97_RECMUX_MIC           0x0000
+#define AC97_RECMUX_CD            0x0101
+#define AC97_RECMUX_VIDEO         0x0202       /* not used */
+#define AC97_RECMUX_AUX           0x0303      
+#define AC97_RECMUX_LINE          0x0404      
+#define AC97_RECMUX_STEREO_MIX    0x0505
+#define AC97_RECMUX_MONO_MIX      0x0606
+#define AC97_RECMUX_PHONE         0x0707
+
+
+/* general purpose register bit defines */
+#define AC97_GP_LPBK              0x0080       /* Loopback mode */
+#define AC97_GP_MS                0x0100       /* Mic Select 0=Mic1, 1=Mic2 */
+#define AC97_GP_MIX               0x0200       /* Mono output select 0=Mix, 1=Mic */
+#define AC97_GP_RLBK              0x0400       /* Remote Loopback - Modem line codec */
+#define AC97_GP_LLBK              0x0800       /* Local Loopback - Modem Line codec */
+#define AC97_GP_LD                0x1000       /* Loudness 1=on */
+#define AC97_GP_3D                0x2000       /* 3D Enhancement 1=on */
+#define AC97_GP_ST                0x4000       /* Stereo Enhancement 1=on */
+#define AC97_GP_POP               0x8000       /* Pcm Out Path, 0=pre 3D, 1=post 3D */
+
+
+/* powerdown control and status bit defines */
+
+/* status */
+#define AC97_PWR_MDM              0x0010       /* Modem section ready */
+#define AC97_PWR_REF              0x0008       /* Vref nominal */
+#define AC97_PWR_ANL              0x0004       /* Analog section ready */
+#define AC97_PWR_DAC              0x0002       /* DAC section ready */
+#define AC97_PWR_ADC              0x0001       /* ADC section ready */
+
+/* control */
+#define AC97_PWR_PR0              0x0100       /* ADC and Mux powerdown */
+#define AC97_PWR_PR1              0x0200       /* DAC powerdown */
+#define AC97_PWR_PR2              0x0400       /* Output mixer powerdown (Vref on) */
+#define AC97_PWR_PR3              0x0800       /* Output mixer powerdown (Vref off) */
+#define AC97_PWR_PR4              0x1000       /* AC-link powerdown */
+#define AC97_PWR_PR5              0x2000       /* Internal Clk disable */
+#define AC97_PWR_PR6              0x4000       /* HP amp powerdown */
+#define AC97_PWR_PR7              0x8000       /* Modem off - if supported */
+
+/* useful power states */
+#define AC97_PWR_D0               0x0000      /* everything on */
+#define AC97_PWR_D1              AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4
+#define AC97_PWR_D2              AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
+#define AC97_PWR_D3              AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
+#define AC97_PWR_ANLOFF          AC97_PWR_PR2|AC97_PWR_PR3  /* analog section off */
+
+/* Total number of defined registers.  */
+#define AC97_REG_CNT 64
+
+
+/* OSS interface to the ac97s.. */
+#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\
+	SOUND_MASK_LINE|SOUND_MASK_CD|\
+	SOUND_MIXER_ALTPCM|SOUND_MASK_IGAIN|\
+	SOUND_MASK_LINE1|SOUND_MASK_VIDEO)
+
+#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
+	SOUND_MASK_BASS|SOUND_MASK_TREBLE|\
+	SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\
+	SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT)
+
+#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
+	SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
+	SOUND_MASK_PHONEIN)
+
+#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) )
+
+struct ac97_codec {
+	/* AC97 controller connected with */
+	void *private_data;
+
+	char *name;
+	int id;
+	int dev_mixer; 
+
+	/* codec specific init/reset routines, used mainly for 4 or 6 channel support */
+	int  (*codec_init)  (struct ac97_codec *codec);
+
+	/* controller specific lower leverl ac97 accessing routines */
+	u16  (*codec_read)  (struct ac97_codec *codec, u8 reg);
+	void (*codec_write) (struct ac97_codec *codec, u8 reg, u16 val);
+
+	/* OSS mixer masks */
+	int modcnt;
+	int supported_mixers;
+	int stereo_mixers;
+	int record_sources;
+	
+	/* OSS mixer interface */
+	int  (*read_mixer) (struct ac97_codec *codec, int oss_channel);
+	void (*write_mixer)(struct ac97_codec *codec, int oss_channel,
+			    unsigned int left, unsigned int right);
+	int  (*recmask_io) (struct ac97_codec *codec, int rw, int mask);
+	int  (*mixer_ioctl)(struct ac97_codec *codec, unsigned int cmd, unsigned long arg);
+
+	/* saved OSS mixer states */
+	unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+};
+
+extern int ac97_probe_codec(struct ac97_codec *);
+#endif
diff -u --recursive --new-file v2.3.41/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.3.41/linux/drivers/sound/trident.c	Tue Jan 11 22:31:41 2000
+++ linux/drivers/sound/trident.c	Fri Jan 28 19:36:23 2000
@@ -29,16 +29,36 @@
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  *  History
+ *  v0.11 Jan 27 2000 Ollie Lho
+ *	DMA bug, scheduler latency, second try
+ *  v0.10 Jan 24 2000 Ollie Lho
+ *	DMA bug fixed, found kernel scheduling problem
+ *  v0.09 Jan 20 2000 Ollie Lho
+ *	Clean up of channel register access routine (prepare for channel binding)
+ *  v0.08 Jan 14 2000 Ollie Lho
+ *	Isolation of AC97 codec code
+ *  v0.07 Jan 13 2000 Ollie Lho
+ *	Get rid of ugly old low level access routines (e.g. CHRegs.lp****)
+ *  v0.06 Jan 11 2000 Ollie Lho
+ *	Preliminary support for dual (more ?) AC97 codecs
  *  v0.05 Jan 08 2000 Luca Montecchiani <m.luca@iname.com>
- *     adapt to 2.3.x new __setup/__initcall
+ *	adapt to 2.3.x new __setup/__init call
  *  v0.04 Dec 31 1999 Ollie Lho
- *	Multiple Open, useing Middle Loop Interrupt to smooth playback
+ *	Multiple Open, using Middle Loop Interrupt to smooth playback
  *  v0.03 Dec 24 1999 Ollie Lho
  *	mem leak in prog_dmabuf and dealloc_dmabuf removed
  *  v0.02 Dec 15 1999 Ollie Lho
  *	SiS 7018 support added, playback O.K.
  *  v0.01 Alan Cox et. al.
  *	Initial Release in kernel 2.3.30, does not work
+ * 
+ *  ToDo
+ *	Clean up of low level channel register access code. (done)
+ *        Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done)
+ *	Dual AC97 codecs support (done partially, need channel binding to test)
+ *	Recording support
+ *	Mmap support
+ *	"Channel Binding" ioctl extension
  */
       
 #include <linux/config.h>
@@ -66,34 +86,40 @@
 #endif
 
 #include "trident.h"
-#include "ac97.h"
+#include "ac97_codec.h"
 
 #undef DEBUG
 
-#define DRIVER_VERSION "0.05"
-
-#define TRIDENT_FMT_STEREO     0x01
-#define TRIDENT_FMT_16BIT      0x02
-#define TRIDENT_FMT_MASK       0x03
-#define TRIDENT_DAC_SHIFT      0   
-#define TRIDENT_ADC_SHIFT      4
-
-#define TRIDENT_ENABLE_PE      1
-#define TRIDENT_ENABLE_RE      2
-#define DAC_RUNNING            1
-#define ADC_RUNNING            2
+#define DRIVER_VERSION "0.11"
 
+/* magic numbers to protect our data structures */
 #define TRIDENT_CARD_MAGIC	0x5072696E /* "Prin" */
 #define TRIDENT_STATE_MAGIC	0x63657373 /* "cess" */
 
-/* number of instances of opening /dev/dsp, can your CPU handle this ? */
-#define NR_DSPS		32
+/* The first 32 channels are called Bank A. They are (should be) reserved
+   for MIDI synthesizer. But since that is not supported yet, we can (ab)use
+   them to play PCM samples */
+#undef ABUSE_BANK_A
+
+/* maxinum number of instances of opening /dev/dspN, can your CPU handle this ?
+   NOTE: If /dev/dsp is opened O_RDWR (i.e. full duplex) it will consume 2 HW
+   channels */
+#ifdef ABUSE_BANK_A
+#define NR_HW_CH		64
+#else
+#define NR_HW_CH		32
+#endif
+
+/* maxinum nuber of AC97 codecs connected, AC97 2.0 defined 4, but 7018 and 4D-NX only
+   have 2 SDATA_IN lines (currently) */
+#define NR_AC97		2
 
+/* minor number of /dev/dspW */
 #define SND_DEV_DSP16	5 
 
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-static const char *sample_format[] = {"8 bits Mono", "8 bits Stereo", "16 bits Mono", "16 bits Stereo"};
+
 static const char invalid_magic[] = KERN_CRIT "trident: invalid magic value in %s\n";
 
 struct pci_audio_info {
@@ -108,52 +134,12 @@
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7018, "SiS 7018 PCI Audio"}
 };
 
-static struct {
-	unsigned int id;
-	char *name;
-} snd_ac97_codec_ids[] = {
-	{0x414B4D00, "Asahi Kasei AK4540"    },
-	{0x41445340, "Analog Devices AD1881" },
-	{0x43525900, "Cirrus Logic CS4297"   },
-	{0x43525913, "Cirrus Logic CS4297A"  },
-	{0x43525931, "Cirrus Logic CS4299"   },
-	{0x4e534331, "National Semiconductor LM4549"},
-	{0x83847600, "SigmaTel STAC????"     },
-	{0x83847604, "SigmaTel STAC9701/3/4/5"},
-	{0x83847605, "SigmaTel STAC9704"      },
-	{0x83847608, "SigmaTel STAC9708"      },
-	{0x83847609, "SigmaTel STAC9721/23"   },
-	{0x00000000, NULL}
-};
-
-typedef struct tChannelControl
-{
-    // register data
-    unsigned int *  lpChStart;
-    unsigned int *  lpChStop;
-    unsigned int *  lpChAint;
-    unsigned int *  lpChAinten;
-
-    // register addresses
-    unsigned int *  lpAChStart;
-    unsigned int *  lpAChStop;
-    unsigned int *  lpAChAint;
-    unsigned int *  lpAChAinten;
-    
-    unsigned int data[16];
-
-} CHANNELCONTROL;
-
 /* "software" or virtual channel, an instance of opened /dev/dsp */
 struct trident_state {
 	unsigned int magic;
 	struct trident_card *card;	/* Card info */
 
-	/* wave stuff */
-	unsigned int rateadc, ratedac;
-	unsigned char fmt, enable;
-
-	/* single opne lock mechanism, should be removed */
+	/* single open lock mechanism, only used for recording */
 	struct semaphore open_sem;
 	wait_queue_head_t open_wait;
 
@@ -164,26 +150,33 @@
 	int virt;
 
 	struct dmabuf {
+		/* wave sample stuff */
+		unsigned int rate;
+		unsigned char fmt, enable;
+
+		/* hardware channel */
+		struct trident_channel *channel;
+
+		/* OSS buffer manangemeent stuff */
 		void *rawbuf;
 		unsigned buforder;
 		unsigned numfrag;
 		unsigned fragshift;
 
-		/* hardware channel number */
-		int chan;
+		/* our buffer acts like a circular ring */
+		unsigned hwptr;		/* where dma last started, update by update_ptr */
+		unsigned swptr;		/* where driver last clear/filled, updated by read/write */
+		int count;		/* bytes to be comsumed by dma machine */
+		unsigned total_bytes;	/* total bytes dmaed by hardware */
 
-		/* XXX zab - swptr only in here so that it can be referenced by
-		   clear_advance, as far as I can tell :( */
-		unsigned hwptr, swptr;
-		unsigned total_bytes;
-		int count;
-		unsigned error; /* over/underrun */
-		wait_queue_head_t wait;
+		unsigned error;		/* number of over/underruns */
+		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
 
 		/* redundant, but makes calculations easier */
 		unsigned fragsize;
 		unsigned dmasize;
 		unsigned fragsamples;
+
 		/* OSS stuff */
 		unsigned mapped:1;
 		unsigned ready:1;
@@ -192,44 +185,45 @@
 		int ossmaxfrags;
 		unsigned subdivision;
 	} dma_dac, dma_adc;
-
-	u8 bDMAStart;
-
 };
 
 /* hardware channels */
 struct trident_channel {
-	int chan; /* channel number */
-	u32 lba;
-	u32 eso;
+	int  num;	/* channel number */
+	u32 lba;	/* reg 0xe4 */
+	u32 eso;	/* reg 0xe8 */
 	u32 delta;
-	u16 attribute;
-	
+	u16 attribute;	/* reg 0xec */
+	u16 fm_vol;
+	u32 control;	/* reg 0xf0 */
 };
 
-struct trident_pcm_bank {
-	/* registers to control bank operations */
+struct trident_pcm_bank_address {
 	u32 start;
 	u32 stop;
 	u32 aint;
 	u32 aint_en;
+};
+static struct trident_pcm_bank_address bank_a_addrs =
+{
+	T4D_START_A,
+	T4D_STOP_A,
+	T4D_AINT_A,
+	T4D_AINTEN_A
+};
+static struct trident_pcm_bank_address bank_b_addrs =
+{
+	T4D_START_B,
+	T4D_STOP_B,
+	T4D_AINT_B,
+	T4D_AINTEN_B
+};
+struct trident_pcm_bank {
+	/* register addresses to control bank operations */
+	struct trident_pcm_bank_address *addresses;
 	/* each bank has 32 channels */
 	u32 bitmap; /* channel allocation bitmap */
-	//struct trident_channel channels[32];
-};
-
-struct trident_mixer {
-	int modcnt;
-	int supported_mixers;
-	int stereo_mixers;
-	int record_sources;
-
-	/* the caller must guarantee arg sanity before calling these */
-	/* int (*read_mixer)(struct trident_card *card, int index);*/
-	void (*write_mixer)(struct trident_card *card,int mixer, unsigned int left,
-			    unsigned int right);
-	int (*recmask_io)(struct trident_card *card,int rw,int mask);
-	unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
+	struct trident_channel channels[32];
 };
 
 struct trident_card {
@@ -239,7 +233,7 @@
 	struct trident_card *next;
 
 	/* The trident has a certain amount of cross channel interaction
-	   so we use a single per card lock */	   
+	   so we use a single per card lock */
 	spinlock_t lock;
 
 	/* PCI device stuff */
@@ -249,286 +243,225 @@
 
 	/* soundcore stuff */
 	int dev_audio;
-	int dev_mixer;
 
-	struct trident_mixer mix;
-	struct trident_state *channels[NR_DSPS];
+	/* structures for abstraction of hardware facilities, codecs, banks and channels*/
+	struct ac97_codec *ac97_codec[NR_AC97];
+	struct trident_pcm_bank banks[NR_BANKS];
+	struct trident_state *states[NR_HW_CH];
 
 	/* hardware resources */
 	unsigned long iobase;
 	u32 irq;
-
-	/* hardware channel allocation bitmap */
-	u32 bitmap[2];
-
-	/* ugly stupid thing, remove ASAP */
-	CHANNELCONTROL ChRegs;
-	int ChanDwordCount;
 };
 
 static struct trident_card *devs = NULL;
 
-/*
- *	Trident support library routines
- */
- 
-/*---------------------------------------------------------------------------
-   void ResetAinten( struct trident_state *trident, int ChannelNum)
-  
-   Description: This routine will disable interrupts and ack any 
-		existing interrupts for specified channel.
-  
-   Parameters:	trident - pointer to target device class for 4DWave.
-		ChannelNum - channel number 
-  
-   returns:	TRUE if everything went ok, else FALSE.
-  
-  ---------------------------------------------------------------------------*/
-
-static void ResetAinten(struct trident_card * trident, int ChannelNum)
-{
-	unsigned int dwMask;
-	unsigned int x = ChannelNum >> 5;
-	unsigned int ChanDwordCount = trident->ChanDwordCount;
-
-	IReadAinten(&trident->ChRegs);
-	dwMask = 1 << (ChannelNum & 0x1f);
-	trident->ChRegs.lpChAinten[x] &= ~dwMask;
-	IWriteAinten(&trident->ChRegs);
-	// Ack the channel in case the interrupt was set before we disable it.
-	outl(dwMask, TRID_REG(trident, trident->ChRegs.lpAChAint[x]));
-}
-
-/*---------------------------------------------------------------------------
-   void EnableEndInterrupts( struct trident_card *trident)
-  
-   Description: This routine will enable end of loop interrupts.
-		End of loop interrupts will occur when a running
-		channel reaches ESO.
-  
-   Parameters:	trident - pointer to target device class for 4DWave.
-  
-   returns:	TRUE if everything went ok, else FALSE.
-  
-  ---------------------------------------------------------------------------*/
+static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
+static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg);
 
-static int trident_enable_end_interrupts(struct trident_card * trident)
+static int trident_open_mixdev(struct inode *inode, struct file *file);
+static int trident_release_mixdev(struct inode *inode, struct file *file);
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+				unsigned long arg);
+static loff_t trident_llseek(struct file *file, loff_t offset, int origin);
+
+static int trident_enable_loop_interrupts(struct trident_card * card)
 {
 	u32 global_control;
 
-	global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
+	global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
 
-	switch (trident->pci_id)
+	switch (card->pci_id)
 	{
 	case PCI_DEVICE_ID_SI_7018:
-		global_control |= (ENDLP_IE | BANK_B_EN);
+		global_control |= (ENDLP_IE | MIDLP_IE| BANK_B_EN);
 		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		global_control |= ENDLP_IE;
+		global_control |= (ENDLP_IE | MIDLP_IE);
 		break;
 	default:
 		return FALSE;
 	}
 
-	outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
 
 #ifdef DEBUG
-	printk("trident: Enable End Interrupts, globctl = 0x%08X\n", global_control);
+	printk("trident: Enable Loop Interrupts, globctl = 0x%08X\n",
+	       global_control);
 #endif
 	return (TRUE);
 }
 
-static int trident_enable_middle_interrupts(struct trident_card * trident)
+static int trident_disable_loop_interrupts(struct trident_card * card)
 {
 	u32 global_control;
 
-	global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
-
-	switch (trident->pci_id)
-	{
-	case PCI_DEVICE_ID_SI_7018:
-		global_control |= (MIDLP_IE | BANK_B_EN);
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-	default:
-		global_control |= MIDLP_IE;
-		break;
-	}
-
-	outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+	global_control = inl(TRID_REG(card, T4D_LFO_GC_CIR));
+	global_control &= ~(ENDLP_IE | MIDLP_IE);
+	outl(global_control, TRID_REG(card, T4D_LFO_GC_CIR));
 
 #ifdef DEBUG
-	printk("trident: Enable Middle Interrupts, globctl = 0x%08X\n", global_control);
+	printk("trident: Disabled Loop Interrupts, globctl = 0x%08X\n",
+	       global_control);
 #endif
 	return (TRUE);
 }
-/*---------------------------------------------------------------------------
-   void DisableEndInterrupts( struct trident_card *trident)
-  
-   Description: This routine will disable end of loop interrupts.
-		End of loop interrupts will occur when a running
-		channel reaches ESO.
-  
-   Parameters:	
-		trident - pointer to target device class for 4DWave.
-  
-   returns:	TRUE if everything went ok, else FALSE.
-  
-  ---------------------------------------------------------------------------*/
 
-static int trident_disable_end_interrupts(struct trident_card * trident)
+static void trident_enable_voice_irq(struct trident_card * card, unsigned int channel)
 {
-	u32 global_control;
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 reg, addr = bank->addresses->aint_en;
 
-	global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
-	global_control &= ~ENDLP_IE;
-	outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+	reg = inl(TRID_REG(card, addr));
+	reg |= mask;
+	outl(reg, TRID_REG(card, addr));
 
 #ifdef DEBUG
-	printk("trident: Disabled End Interrupts, globctl = 0x%08X\n", global_control);
+	reg = inl(TRID_REG(card, T4D_AINTEN_B));
+	printk("trident: enabled IRQ on channel %d, AINTEN_B = 0x%08x\n",
+	       channel, reg);
 #endif
-	return (TRUE);
 }
 
-static int trident_disable_middle_interrupts(struct trident_card * trident)
+static void trident_disable_voice_irq(struct trident_card * card, unsigned int channel)
 {
-	u32 global_control;
-
-	global_control = inl(TRID_REG(trident, T4D_LFO_GC_CIR));
-	global_control &= ~MIDLP_IE;
-	outl(global_control, TRID_REG(trident, T4D_LFO_GC_CIR));
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 reg, addr = bank->addresses->aint_en;
+	
+	reg = inl(TRID_REG(card, addr));
+	reg &= ~mask;
+	outl(reg, TRID_REG(card, addr));
+	
+	/* Ack the channel in case the interrupt was set before we disable it. */
+	outl(mask, TRID_REG(card, bank->addresses->aint));
 
 #ifdef DEBUG
-	printk("trident: Disabled Middle Interrupts, globctl = 0x%08X\n", global_control);
+	reg = inl(TRID_REG(card, T4D_AINTEN_B));
+	printk("trident: disabled IRQ on channel %d, AINTEN_B = 0x%08x\n",
+	       channel, reg);
 #endif
-	return (TRUE);
 }
-/*---------------------------------------------------------------------------
-   void trident_enable_voice_irq( unsigned int HwChannel )
-  
-    Description: Enable an interrupt channel, any channel 0 thru n.
-		 This routine automatically handles the fact that there are
-		 more than 32 channels available.
-  
-    Parameters : HwChannel - Channel number 0 thru n.
-		 trident - pointer to target device class for 4DWave.
-  
-    Return Value: None.
-  
-  ---------------------------------------------------------------------------*/
-void trident_enable_voice_irq(struct trident_card * trident, unsigned int channel)
-{
-	unsigned int bank, mask, ChanDwordCount;
-	u32 reg;
 
-	bank = channel >> 5;
-	mask = 1 << (channel & 0x1f);
+static void trident_start_voice(struct trident_card * card, unsigned int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 addr = bank->addresses->start;
 
-	ChanDwordCount = trident->ChanDwordCount;
+#ifdef DEBUG
+	u32 reg;
+#endif
 
-	IReadAinten(&trident->ChRegs);
-	trident->ChRegs.lpChAinten[bank] |= mask;
-	IWriteAinten(&trident->ChRegs);
+	outl(mask, TRID_REG(card, addr));
 
 #ifdef DEBUG
-	reg = inl(TRID_REG(trident, T4D_AINTEN_B));
-	printk("trident: enabled IRQ on channel %d\n", channel);
+	reg = inl(TRID_REG(card, T4D_START_B));
+	printk("trident: start voice on channel %d, START_B  = 0x%08x\n",
+	       channel, reg);
 #endif
 }
 
-/*---------------------------------------------------------------------------
-   void trident_disable_voice_irq( unsigned int HwChannel )
-  
-    Description: Disable an interrupt channel, any channel 0 thru n.
-		 This routine automatically handles the fact that there are
-		 more than 32 channels available.
-  
-    Parameters : HwChannel - Channel number 0 thru n.
-		 trident - pointer to target device class for 4DWave.
-  
-    Return Value: None.
-  
-  ---------------------------------------------------------------------------*/
-void trident_disable_voice_irq(struct trident_card * trident, unsigned int channel)
+static void trident_stop_voice(struct trident_card * card, unsigned int channel)
 {
-	unsigned int bank, mask, ChanDwordCount;
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 addr = bank->addresses->stop;
+
+#ifdef DEBUG
 	u32 reg;
+#endif
 
-	bank = channel >> 5;
-	mask = 1 << (channel & 0x1f);
+	outl(mask, TRID_REG(card, addr));
+
+#ifdef DEBUG
+	reg = inl(TRID_REG(card, T4D_STOP_B));
+	printk("trident: stop voice on channel %d,  STOP_B  = 0x%08x\n",
+	       channel, reg);
+#endif
+}
+
+static int trident_check_channel_interrupt(struct trident_card * card, int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 reg, addr = bank->addresses->aint;
 
-	ChanDwordCount = trident->ChanDwordCount;
-	IReadAinten(&trident->ChRegs);
-	trident->ChRegs.lpChAinten[bank] &= ~mask;
-	IWriteAinten(&trident->ChRegs);
+	reg = inl(TRID_REG(card, addr));
 
 #ifdef DEBUG
-	reg = inl(TRID_REG(trident, T4D_AINTEN_B));
-	printk("trident: disabled IRQ on channel %d\n", channel);
+	if (reg & mask)
+		printk("trident: channel %d has interrupt, AINT_B = 0x%08x\n",
+		       channel, reg);
 #endif
+	return (reg & mask) ? TRUE : FALSE;
 }
 
-/*---------------------------------------------------------------------------
-   unsigned int AllocateChannelPCM( void )
-  
-    Description: Allocate hardware channel by reverse order (63-0).
-  
-    Parameters :  trident - pointer to target device class for 4DWave.
-  
-    Return Value: hardware channel - 0-63 or -1 when no channel is available
-  
-  ---------------------------------------------------------------------------*/
+static void trident_ack_channel_interrupt(struct trident_card * card, int channel)
+{
+	unsigned int mask = 1 << (channel & 0x1f);
+	struct trident_pcm_bank *bank = &card->banks[channel >> 5];
+	u32 reg, addr = bank->addresses->aint;
+
+	reg = inl(TRID_REG(card, addr));
+	reg &= mask;
+	outl(reg, TRID_REG(card, addr));
+
+#ifdef DEBUG
+	reg = inl(TRID_REG(card, T4D_AINT_B));
+	printk("trident: Ack channel %d interrupt, AINT_B = 0x%08x\n",
+	       channel, reg);
+#endif
+}
 
-static int trident_alloc_pcm_channel(struct trident_card *trident)
+static struct trident_channel * trident_alloc_pcm_channel(struct trident_card *card)
 {
+	struct trident_pcm_bank *bank;
 	int idx;
 
-	if (trident->bitmap[BANK_B] == ~0UL) {
+	bank = &card->banks[BANK_B];
+	if (bank->bitmap == ~0UL) {
 		/* no more free channels avaliable */
 		printk(KERN_ERR "trident: no more channels available on Bank B.\n");
-		return -1;
+#ifdef ABUSE_BANK_A
+		goto bank_a;
+#endif
+		return NULL;
 	}
 	for (idx = 31; idx >= 0; idx--) {
-		if (!(trident->bitmap[BANK_B] & (1 << idx))) {
-			trident->bitmap[BANK_B] |= 1 << idx;
-			return idx + 32;
+		if (!(bank->bitmap & (1 << idx))) {
+			struct trident_channel *channel = &bank->channels[idx];
+			bank->bitmap |= 1 << idx;
+			channel->num = idx + 32;
+			return channel;
 		}
 	}
 
 #ifdef ABUSE_BANK_A
 	/* channels in Bank A should be reserved for synthesizer 
 	   not for normal use (channels in Bank A can't record) */
-	if (trident->bitmap[BANK_A] == ~0UL) {
+ bank_a:
+	bank = &card->banks[BANK_A];
+	if (bank->bitmap == ~0UL) {
 		/* no more free channels avaliable */
-		printk(KERN_ERR "trident: no channels available on Bank A.\n");
-		return -1;
+		printk(KERN_ERR "trident: no more channels available on Bank A.\n");
+		return NULL;
 	}
 	for (idx = 31; idx >= 0; idx--) {
-		if (!(trident->bitmap[BANK_A] & (1 << idx))) {
-			trident->bitmap[BANK_A] |= 1 << idx;
-			return idx;
+		if (!(bank->bitmap & (1 << idx))) {
+			struct trident_channel *channel = &bank->channels[idx];
+			banks->bitmap |= 1 << idx;
+			channel->num = idx;
+			return channels;
 		}
 	}
 #endif
-
-	return -1;
+	return NULL;
 }
 
-/*---------------------------------------------------------------------------
-   void FreeChannelPCM( int channel )
-  
-    Description: Free hardware channel.
-  
-    Parameters :  trident - pointer to target device class for 4DWave.
-                  channel - hardware channel number 0-63
-  
-    Return Value: none
-  
-  ---------------------------------------------------------------------------*/
-
-static void trident_free_pcm_channel(struct trident_card *trident, int channel)
+static void trident_free_pcm_channel(struct trident_card *card, int channel)
 {
 	int bank;
 
@@ -543,236 +476,74 @@
 	bank = channel >> 5;
 	channel = channel & 0x1f;
 
-	if (trident->bitmap[bank] & (1 << (channel))) {
-		trident->bitmap[bank] &= ~(1 << (channel));
+	if (card->banks[bank].bitmap & (1 << (channel))) {
+		card->banks[bank].bitmap &= ~(1 << (channel));
 	}
 }
 
-/*---------------------------------------------------------------------------
-   void trident_start_voice( ULONG HwChannel )
-  
-    Description: Start a channel, any channel 0 thru n.
-		 This routine automatically handles the fact that there are
-		 more than 32 channels available.
-  
-    Parameters : HwChannel - Channel number 0 thru n.
-		 trident - pointer to target device class for 4DWave.
-  
-    Return Value: None.
-  
-  ---------------------------------------------------------------------------*/
-void trident_start_voice(struct trident_card * trident, unsigned int channel)
+/* called with spin lock held */
+static int trident_load_channel_registers(struct trident_card *card, u32 *data, unsigned int channel)
 {
-	unsigned int bank = channel >> 5;
-	unsigned int mask = 1 << (channel & 0x1f);
+	int i;
 
-	outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStart[bank]));
-#ifdef DEBUG
-	printk("trident: start voice on channel %d\n", channel);
-#endif
-}
+	if (channel > 63)
+		return FALSE;
 
-/*---------------------------------------------------------------------------
-   void trident_stop_voice( ULONG HwChannel )
-  
-    Description: Stop a channel, any channel 0 thru n.
-		 This routine automatically handles the fact that there are
-		 more than 32 channels available.
-  
-    Parameters : HwChannel - Channel number 0 thru n.
-		 trident - pointer to target device class for 4DWave.
-  
-    Return Value: None.
-  
-  ---------------------------------------------------------------------------*/
-void trident_stop_voice(struct trident_card * trident, unsigned int channel)
-{
-	unsigned int bank = channel >> 5;
-	unsigned int mask = 1 << (channel & 0x1f);
+	/* select hardware channel to write */
+	outb(channel, TRID_REG(card, T4D_LFO_GC_CIR));
+	/* output the channel registers */
+	for (i = 0; i < CHANNEL_REGS; i++) {
+		outl(data[i], TRID_REG(card, CHANNEL_START + 4*i));
+	}
 
-	outl(mask, TRID_REG(trident, trident->ChRegs.lpAChStop[bank]));
-#ifdef DEBUG
-	printk("trident: stop voice on channel %d\n", channel);
-#endif
+	return TRUE;
 }
 
-/*---------------------------------------------------------------------------
-   int DidChannelInterrupt( )
-  
-   Description:	 Check if interrupt channel occurred.
-  
-   Parameters :	 trident - pointer to target device class for 4DWave.
-  
-   Return Value: TRUE if interrupt occurred, else FALSE.
-  
-  ---------------------------------------------------------------------------*/
-static int trident_check_channel_interrupt(struct trident_card * trident, int channel)
+/* called with spin lock held */
+static int trident_write_voice_regs(struct trident_state *state, unsigned int rec)
 {
-	unsigned int ChanDwordCount = NUM_BANKS;
-	unsigned int bank = channel >> 5;
-	unsigned int mask = 1 << (channel & 0x1f);
-
-	ReadAint(&trident->ChRegs);
-
-#ifdef DEBUG
-	if (trident->ChRegs.lpChAint[bank] & mask)
-		printk("trident: channel %d has interrupt\n", channel);
-#endif	
-	return (trident->ChRegs.lpChAint[bank] & mask) ? TRUE : FALSE;
-}
+	unsigned int data[CHANNEL_REGS + 1];
+	struct trident_channel *channel;
 
-/*---------------------------------------------------------------------------
-   void AckChannelInterrupt( )
-  
-   Description:	 Acknowledge the interrupt bit for channel intrs.
-  
-   Parameters :	 trident - pointer to target device class for 4DWave.
-  
-   Return Value: None
-  
-  ---------------------------------------------------------------------------*/
-static void trident_ack_channel_interrupt(struct trident_card * trident, int channel)
-{
-	unsigned int ChanDwordCount = NUM_BANKS;
-	unsigned int bank = channel >> 5;
-	unsigned int mask = 1 << (channel & 0x1f);
+	if (rec)
+		channel = state->dma_adc.channel;
+	else
+		channel = state->dma_dac.channel;
 
-	ReadAint(&trident->ChRegs);
-	trident->ChRegs.lpChAint[bank] &= mask;
-	IWriteAint(&trident->ChRegs);
-}
-
-/*---------------------------------------------------------------------------
-   int trident_load_hw_delta( unsigned int HwChannel, unsigned int Delta )
-  
-   Description: This routine writes Delta to the hardware.
-  
-   Parameters:	Delta - data to write (2 Bytes only)
-		HwChannel - Hardware channel to write to.
-		trident - pointer to target device class for 4DWave.
-  
-   Returns:	TRUE if all goes well, else FALSE. 
-  
-  ---------------------------------------------------------------------------*/
-static int trident_load_hw_delta (struct trident_card * trident, unsigned int channel,
-				  unsigned short delta)
-{
-	/* select a channel for output */
-	outb(channel, TRID_REG(trident, T4D_LFO_GC_CIR));
+	data[1] = channel->lba;
+	data[4] = channel->control;
 
-	switch (trident->pci_id)
+	switch (state->card->pci_id)
 	{
 	case PCI_DEVICE_ID_SI_7018:
+		data[0] = 0; /* Current Sample Offset */
+		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+		data[3] = (channel->attribute << 16) | (channel->fm_vol & 0xffff);
+		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-		outw((u16) delta, TRID_REG(trident, CH_DX_ESO_DELTA));
+		data[0] = 0; /* Current Sample Offset */
+		data[2] = (channel->eso << 16) | (channel->delta & 0xffff);
+		data[3] = channel->fm_vol & 0xffff;
 		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		outb(delta	 & 0xff, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
-		outb((delta >> 8)& 0xff, TRID_REG(trident, CH_NX_DELTA_ESO + 3));
+		data[0] = (channel->delta << 24);
+		data[2] = ((channel->delta << 24) & 0xff000000) | (channel->eso & 0x00ffffff);
+		data[3] = channel->fm_vol & 0xffff;
 		break;
 	default:
 		return FALSE;
 	}
-	return TRUE;
-}
 
-/*---------------------------------------------------------------------------
-   int LoadVirtualChannel( ULONG *Data, ULONG HwChannel)
-  
-   Description: This routine writes all required channel registers to hardware.
-  
-   Parameters:	*Data - a pointer to the data to write (5 ULONGS always).
-		HwChannel - Hardware channel to write to.
-		trident - pointer to target device class for 4DWave.
-  
-   Returns:	TRUE if all goes well, else FALSE. 
-  
-  ---------------------------------------------------------------------------*/
-static int LoadVirtualChannel(struct trident_card * trident, unsigned int *Data, unsigned int HwChannel)
-{
-	unsigned int ChanData[CHANNEL_REGS];
-	unsigned int ULONGSToDo = CHANNEL_REGS;
-	unsigned int i;
-	unsigned int Address = CHANNEL_START;
-
-	/* Copy the data first... Hack... Before mucking with Volume! */
-	memcpy((unsigned char *) ChanData, (unsigned char *) Data, ULONGSToDo * 4);
-
-	outb((unsigned char) HwChannel, TRID_REG(trident, T4D_LFO_GC_CIR));
-
-	for (i = 0; i < ULONGSToDo; i++, Address += 4)
-		outl(ChanData[i], TRID_REG(trident, Address));
-#ifdef DEBUG
-	printk("(trident) load virtual channel %d\n", HwChannel);
-#endif
-	return TRUE;
-}
-
-/*---------------------------------------------------------------------------
-   trident_write_voice_regs
-  
-   Description: This routine will write the 5 hardware channel registers
-		to hardware.
-  
-   Paramters:	trident - pointer to target device class for 4DWave.
-		Channel - Real or Virtual channel number.
-		Each register field.
-  
-   Returns:	TRUE if all goes well, else FALSE. 
-  
-  ---------------------------------------------------------------------------*/
-int trident_write_voice_regs(struct trident_card * trident,
-			 unsigned int Channel,
-			 unsigned int LBA,
-			 unsigned int CSO,
-			 unsigned int ESO,
-			 unsigned int DELTA,
-			 unsigned int ALPHA_FMS,
-			 unsigned int FMC_RVOL_CVOL,
-			 unsigned int GVSEL,
-			 unsigned int PAN,
-			 unsigned int VOL,
-			 unsigned int CTRL,
-			 unsigned int EC)
-{
-	unsigned int ChanData[CHANNEL_REGS + 1], FmcRvolCvol;
-
-	ChanData[1] = LBA;
-	ChanData[4] = (GVSEL << 31) |
-	    ((PAN & 0x0000007f) << 24) |
-	    ((VOL & 0x000000ff) << 16) |
-	    ((CTRL & 0x0000000f) << 12) |
-	    (EC & 0x00000fff);
-
-	FmcRvolCvol = FMC_RVOL_CVOL & 0x0000ffff;
-
-	switch (trident->pci_id)
-	{
-	case PCI_DEVICE_ID_SI_7018:
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-		ChanData[0] = (CSO << 16) | (ALPHA_FMS & 0x0000ffff);
-		ChanData[2] = (ESO << 16) | (DELTA & 0x0000ffff);
-		ChanData[3] = FmcRvolCvol;
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		ChanData[0] = (DELTA << 24) | (CSO & 0x00ffffff);
-		ChanData[2] = ((DELTA << 16) & 0xff000000) | (ESO & 0x00ffffff);
-		ChanData[3] = (ALPHA_FMS << 16) | FmcRvolCvol;
-		break;
-	}
-
-	LoadVirtualChannel(trident, ChanData, Channel);
-
-	return TRUE;
+	return trident_load_channel_registers(state->card, data, channel->num);
 }
 
 static int compute_rate(u32 rate)
 {
 	int delta;
-	// We special case 44100 and 8000 since rounding with the equation
-	// does not give us an accurate enough value. For 11025 and 22050
-	// the equation gives us the best answer. All other frequencies will
-	// also use the equation. JDW
+	/* We special case 44100 and 8000 since rounding with the equation
+	   does not give us an accurate enough value. For 11025 and 22050
+	   the equation gives us the best answer. All other frequencies will
+	   also use the equation. JDW */
 	if (rate == 44100)
 		delta = 0xeb3;
 	else if (rate == 8000)
@@ -784,838 +555,267 @@
 	return delta;
 }
 
-/*---------------------------------------------------------------------------
-   trident_set_dac_rate
-  
-   Description: This routine will set the sample rate for playback.
-  
-   Paramters:	trident - pointer to target device class for 4DWave.
-		rate	- desired sample rate
-		set	- actually write hardware if set is true.
-  
-   Returns:	The rate allowed by device.
-  
-  ---------------------------------------------------------------------------*/
-
-static unsigned int trident_set_dac_rate(struct trident_state * trident,
-					 unsigned int rate, int set)
-{
-	u16 delta;
+/* set playback sample rate */
+static unsigned int trident_set_dac_rate(struct trident_state * state, unsigned int rate)
+{	
+	struct dmabuf *dmabuf = &state->dma_dac;
 
 	if (rate > 48000)
 		rate = 48000;
 	if (rate < 4000)
 		rate = 4000;
 
-	delta = compute_rate(rate);
-	trident->ratedac = rate;
+	dmabuf->rate = rate;
+	dmabuf->channel->delta = compute_rate(rate);
+
+	trident_write_voice_regs(state, 0);
 
-	if (set)
-		trident_load_hw_delta(trident->card, trident->dma_dac.chan,
-				      delta);
-#ifdef DEBUG	 
-	printk("trident: called trident_set_dac_rate : rate = %d, "
-	       "set = %d, delta = 0x%04x\n", rate, set, delta);
+#ifdef DEBUG
+	printk("trident: called trident_set_dac_rate : rate = %d\n", rate);
 #endif
 
 	return rate;
 }
 
-/*---------------------------------------------------------------------------
-   trident_set_adc_rate
-  
-   Description: This routine will set the sample rate for capture.
-  
-   Paramters:	trident - pointer to target device class for 4DWave.
-		rate	- desired sample rate
-		set	- actually write hardware if set is true.
-  
-   Returns:	The rate allowed by device.
-  
-  ---------------------------------------------------------------------------*/
-
-static unsigned int trident_set_adc_rate(struct trident_state * trident,
-					 unsigned int rate, int set)
+/* set recording sample rate */
+static unsigned int trident_set_adc_rate(struct trident_state * state, unsigned int rate)
 {
-	u16 delta;
-
+	struct dmabuf *dmabuf = &state->dma_adc;
 	if (rate > 48000)
 		rate = 48000;
 	if (rate < 4000)
 		rate = 4000;
 
-	delta = compute_rate(rate);
-	trident->ratedac = rate;
+	dmabuf->rate = rate;
+	dmabuf->channel->delta = compute_rate(rate);
 
-#if 0 /* It seems that 4D-Wave can not use wave tables channels for recording */
-	if (set)
-		trident_load_hw_delta(trident->card, trident->dma_adc.chan,
-				      delta);
-#endif
-#ifdef DEBUG	 
-	printk("trident: called trident_set_adc_rate : rate = %d, "
-	       "set = %d, delta = 0x%04x\n", rate, set, delta);
+	trident_write_voice_regs(state, 1);
+
+#ifdef DEBUG
+	printk("trident: called trident_set_adc_rate : rate = %d\n", rate);
 #endif
 	return rate;
 }
- 
-extern __inline__ unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/* Write AC97 mixer registers */
-static void trident_ac97_set(struct trident_card *trident, u8 cmd, u16 val)
-{
-	unsigned int	address, mask, busy;
-	unsigned short	count  = 0xffff;
-	u32 data;
-
-	data = ((u32) val) << 16;
-
-	switch (trident->pci_id)
-	{
-	default:
-	case PCI_DEVICE_ID_SI_7018:
-		address = SI_AC97_WRITE;
-		mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
-		busy = SI_AC97_BUSY_WRITE;
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-		address = DX_ACR0_AC97_W;
-		mask = busy = DX_AC97_BUSY_WRITE;
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		address = NX_ACR1_AC97_W;
-		mask = busy = NX_AC97_BUSY_WRITE;
-		break;
-	}
-
-	do {
-		if ((inw(TRID_REG(trident, address)) & busy) == 0)
-			break;
-	} while (count--);
-	
-	data |= (mask | (cmd & AC97_REG_ADDR));
-
-	if (count == 0) {
-		printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
-		return;
-	}
-	outl(data, TRID_REG(trident, address));
-}
 
-/* Read AC97 codec registers */
-static u16 trident_ac97_get(struct trident_card *trident, u8 cmd)
+/* prepare channel attributes for playback */ 
+static void trident_play_setup(struct trident_state *state)
 {
-	unsigned int address, mask, busy;
-	unsigned short count = 0xffff;
-	u32 data;
+	struct dmabuf *dmabuf = &state->dma_dac;
+	struct trident_channel *channel = dmabuf->channel;
 
-	switch (trident->pci_id)
-	{
-	default:
-	case PCI_DEVICE_ID_SI_7018:
-		address = SI_AC97_READ;
-		mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
-		busy = SI_AC97_BUSY_READ;
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-		address = DX_ACR1_AC97_R;
-		mask = busy = DX_AC97_BUSY_READ;
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		address = NX_ACR2_AC97_R_PRIMARY;
-		mask = NX_AC97_BUSY_READ;
-		busy = 0x0c00;
-		break;
-	}
-
-	data = (mask | (cmd & AC97_REG_ADDR));
-	outl(data, TRID_REG(trident, address));
-
-	do {
-		data = inl(TRID_REG(trident, address));
-		if ((data & busy) == 0)
-			break;
-	} while (count--);
+	channel->lba = virt_to_bus(dmabuf->rawbuf);
+	channel->delta = compute_rate(dmabuf->rate);
 
-	if (count == 0) {
-		printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
-		data = 0;
+	channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
+	channel->eso -= 1;
+
+	if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
+		/* FIXME: channel attributes are configured by ioctls, but it is not implemented
+		   so just set to ZERO for the moment */
+		channel->attribute = 0;
+	} else {
+		channel->attribute = 0;
 	}
-	return ((u16) (data >> 16));
-}
-
-/* OSS interface to the ac97s.. */
 
-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\
-	SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\
-	SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN)
-
-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
-	SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\
-	SOUND_MASK_SPEAKER)
-
-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
-	SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
-	SOUND_MASK_PHONEIN)
-
-#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<<FOO) )
-
-/* this table has default mixer values for all OSS mixers.
-	be sure to fill it in if you add oss mixers
-	to anyone's supported mixer defines */
-
-/* possible __init */
-static struct mixer_defaults {
-	int mixer;
-	unsigned int value;
-} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
-	/* all values 0 -> 100 in bytes */
-	{SOUND_MIXER_VOLUME,	0x3232},
-	{SOUND_MIXER_BASS,	0x3232},
-	{SOUND_MIXER_TREBLE,	0x3232},
-	{SOUND_MIXER_SPEAKER,	0x3232},
-	{SOUND_MIXER_MIC,	0x3232},
-	{SOUND_MIXER_LINE,	0x3232},
-	{SOUND_MIXER_CD,	0x3232},
-	{SOUND_MIXER_VIDEO,	0x3232},
-	{SOUND_MIXER_LINE1,	0x3232},
-	{SOUND_MIXER_PCM,	0x3232},
-	{SOUND_MIXER_IGAIN,	0x3232},
-	{-1,0}
-};
+	channel->fm_vol = 0x0;
 	
-static struct ac97_mixer_hw {
-	unsigned char offset;
-	int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
-	[SOUND_MIXER_VOLUME]	=	{AC97_MASTER_VOL_STEREO,63},
-	[SOUND_MIXER_BASS]	=	{AC97_MASTER_TONE,	15},
-	[SOUND_MIXER_TREBLE]	=	{AC97_MASTER_TONE, 	15},
-	[SOUND_MIXER_SPEAKER]	=	{AC97_PCBEEP_VOL,  	15},
-	[SOUND_MIXER_MIC]	=	{AC97_MIC_VOL,		31},
-	[SOUND_MIXER_LINE]	=	{AC97_LINEIN_VOL,	31},
-	[SOUND_MIXER_CD]	=	{AC97_CD_VOL,		31},
-	[SOUND_MIXER_VIDEO]	=	{AC97_VIDEO_VOL,	31},
-	[SOUND_MIXER_LINE1]	=	{AC97_AUX_VOL,		31},
-	[SOUND_MIXER_PCM]	=	{AC97_PCMOUT_VOL,	31},
-	[SOUND_MIXER_IGAIN]	=	{AC97_RECORD_GAIN,	31}
-};
-
-#if 0 /* *shrug* removed simply because we never used it.
-	 feel free to implement again if needed */
-
-/* reads the given OSS mixer from the ac97
-   the caller must have insured that the ac97 knows
-   about that given mixer, and should be holding a
-   spinlock for the card */
-static int ac97_read_mixer(struct trident_card *card, int mixer) 
-{
-	u16 val;
-	int ret = 0;
-	struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
-	val = trident_ac97_get(card , mh->offset);
-
-	if (AC97_STEREO_MASK & (1<<mixer)) {
-		/* nice stereo mixers .. */
-		int left,right;
-
-		left = (val >> 8)  & 0x7f;
-		right = val  & 0x7f;
-
-		if (mixer == SOUND_MIXER_IGAIN) {
-			right = (right * 100) / mh->scale;
-			left = (left * 100) / mh->scale;
-		else {
-			right = 100 - ((right * 100) / mh->scale);
-			left = 100 - ((left * 100) / mh->scale);
-		}
-
-		ret = left | (right << 8);
-	} else if (mixer == SOUND_MIXER_SPEAKER) {
-		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
-	} else if (mixer == SOUND_MIXER_MIC) {
-		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-	/*  the low bit is optional in the tone sliders and masking
-	    it lets us avoid the 0xf 'bypass'.. */
-	} else if (mixer == SOUND_MIXER_BASS) {
-		ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
-	} else if (mixer == SOUND_MIXER_TREBLE) {
-		ret = 100 - (((val & 0xe) * 100) / mh->scale);
-	}
-
-#ifdef DEBUG
-	printk("trident: read OSS mixer %2d (ac97 register 0x%02x), "
-	       "0x%04x -> 0x%04x\n", mixer, mh->offset, val, ret);
-#endif
-
-	return ret;
-}
-#endif
-
-/* write the OSS encoded volume to the given OSS encoded mixer,
-   again caller's job to make sure all is well in arg land,
-   call with spinlock held */
-static void ac97_write_mixer(struct trident_card *card, int mixer, 
-			     unsigned int left, unsigned int right)
-{
-	u16 val = 0;
-	struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
-#ifdef DEBUG
-	printk("trident: wrote OSS mixer %2d (ac97 register 0x%02x), "
-	       "left vol:%2d, right vol:%2d:",
-	       mixer, mh->offset, left, right);
-#endif
-
-	if (AC97_STEREO_MASK & (1 << mixer)) {
-		/* stereo mixers */
-		if (mixer == SOUND_MIXER_IGAIN) {
-			right = (right * mh->scale) / 100;
-			left = (left * mh->scale) / 100;
-		} else {
-			right = ((100 - right) * mh->scale) / 100;
-			left = ((100 - left) * mh->scale) / 100;
-		}
-
-		val = (left << 8) | right;
-	} else if (mixer == SOUND_MIXER_SPEAKER) {
-		val = (((100 - left) * mh->scale) / 100) << 1;
-	} else if (mixer == SOUND_MIXER_MIC) {
-		val = trident_ac97_get(card , mh->offset) & ~0x801f;
-		val |= (((100 - left) * mh->scale) / 100);
-		/*  the low bit is optional in the tone sliders and masking
-		    it lets us avoid the 0xf 'bypass'.. */
-	} else if (mixer == SOUND_MIXER_BASS) {
-		val = trident_ac97_get(card , mh->offset) & ~0x0f00;
-		val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
-	} else if (mixer == SOUND_MIXER_TREBLE)	 {
-		val = trident_ac97_get(card , mh->offset) & ~0x000f;
-		val |= (((100 - left) * mh->scale) / 100) & 0x000e;
+	channel->control = CHANNEL_LOOP;
+	if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
+		/* 16-bits */
+		channel->control |= CHANNEL_16BITS;
+		/* signed */
+		channel->control |= CHANNEL_SIGNED;
 	}
-
-#ifdef DEBUG
-	printk(" 0x%04x", val);
-#endif
-	trident_ac97_set(card, mh->offset, val);
-
+	if (dmabuf->fmt & TRIDENT_FMT_STEREO)
+		/* stereo */
+		channel->control |= CHANNEL_STEREO;
 #ifdef DEBUG
-	val = trident_ac97_get(card, mh->offset);
-	printk(" -> 0x%04x\n", val);
+	printk("trident: trident_play_setup, LBA = 0x%08x, "
+	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+	       channel->lba, channel->delta, channel->eso, channel->control);
 #endif
+	trident_write_voice_regs(state, 0);
 }
 
-/* the following tables allow us to go from 
-	OSS <-> ac97 quickly. */
-
-enum ac97_recsettings {
-	AC97_REC_MIC=0,
-	AC97_REC_CD,
-	AC97_REC_VIDEO,
-	AC97_REC_AUX,
-	AC97_REC_LINE,
-	AC97_REC_STEREO, /* combination of all enabled outputs..  */
-	AC97_REC_MONO,	      /*.. or the mono equivalent */
-	AC97_REC_PHONE	      
-};
-
-static unsigned int ac97_rm2oss[] = {
-	[AC97_REC_MIC] = SOUND_MIXER_MIC, 
-	[AC97_REC_CD] = SOUND_MIXER_CD, 
-	[AC97_REC_VIDEO] = SOUND_MIXER_VIDEO, 
-	[AC97_REC_AUX] = SOUND_MIXER_LINE1, 
-	[AC97_REC_LINE] = SOUND_MIXER_LINE, 
-	[AC97_REC_PHONE] = SOUND_MIXER_PHONEIN
-};
-
-/* indexed by bit position */
-static unsigned int ac97_oss_rm[] = {
-	[SOUND_MIXER_MIC] = AC97_REC_MIC,
-	[SOUND_MIXER_CD] = AC97_REC_CD,
-	[SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
-	[SOUND_MIXER_LINE1] = AC97_REC_AUX,
-	[SOUND_MIXER_LINE] = AC97_REC_LINE,
-	[SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
-};
-	
-/* read or write the recmask 
-   the ac97 can really have left and right recording
-   inputs independantly set, but OSS doesn't seem to 
-   want us to express that to the user. 
-   the caller guarantees that we have a supported bit set,
-   and they must be holding the card's spinlock */
-static int ac97_recmask_io(struct trident_card *card, int rw, int mask) 
-{
-	unsigned int val;
-
-	if (rw) {
-		/* read it from the card */
-		val = trident_ac97_get(card, 0x1a) & 0x7;
-		return ac97_rm2oss[val];
-	}
-
-	/* else, write the first set in the mask as the
-	   output */	
-
-	val = ffs(mask); 
-	val = ac97_oss_rm[val-1];
-	val |= val << 8;  /* set both channels */
-#ifdef DEBUG
-	printk("trident: setting ac97 recmask to 0x%x\n", val);
-#endif
-	trident_ac97_set(card, 0x1a, val);
-
-	return 0;
-};
-
-/* AC97 codec initialisation. */
-static u16 trident_ac97_init(struct trident_card *trident)
+/* prepare channel attributes for recording */
+static void trident_rec_setup(struct trident_state *state)
 {
-	u16 id1, id2;
-	char *ac97_name = NULL;
-	int i;
+	u16 w;
+	struct trident_card *card = state->card;
+	struct dmabuf *dmabuf = &state->dma_adc;
+	struct trident_channel *channel = dmabuf->channel;
 
-	/* initialize controller side of AC link */
-	switch (trident->pci_id)
+	/* Enable AC-97 ADC (capture) */
+	switch (card->pci_id) 
 	{
 	case PCI_DEVICE_ID_SI_7018:
-		/* disable AC97 GPIO interrupt */
-		outl(0x00, TRID_REG(trident, SI_AC97_GPIO));
-		/* stop AC97 cold reset process */
-		outl(0x00014000, TRID_REG(trident, SI_SERIAL_INTF_CTRL));
+		/* for 7018, the ac97 is always in playback/record (duplex) mode */
 		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-		/* playback on */
-		outl(0x02, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));
+		w = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+		outb(w | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
 		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		/* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
-		outl(0x02, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));
+		w = inw(TRID_REG(card, T4D_MISCINT));
+		outw(w | 0x1000, TRID_REG(card, T4D_MISCINT));
 		break;
+	default:
+		return;
 	}
 
-	/* get some information about our AC97 codec */
-	id1 = trident_ac97_get(trident, AC97_VENDOR_ID1);
-	id2 = trident_ac97_get(trident, AC97_VENDOR_ID2);
-	for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
-		if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
-			ac97_name = snd_ac97_codec_ids[i].name;
-			break;
-		}
-	}
-	if (ac97_name == NULL)
-		ac97_name = "Unknown";
-	printk(KERN_INFO "trident: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
-	       id1, id2, ac97_name);
-
-	/* initialize volume level */
-	trident_ac97_set(trident, AC97_RESET, 0L);
-	trident_ac97_set(trident, AC97_MASTER_VOL_STEREO, 0L);
-	trident_ac97_set(trident, AC97_PCMOUT_VOL, 0L);
-
-	/* set appropriate masks and function pointers */
-	trident->mix.supported_mixers = AC97_SUPPORTED_MASK;
-	trident->mix.stereo_mixers = AC97_STEREO_MASK;
-	trident->mix.record_sources = AC97_RECORD_MASK;
-	/* FIXME: trident->mix.read_mixer = ac97_read_mixer; */
-	trident->mix.write_mixer = ac97_write_mixer;
-	trident->mix.recmask_io = ac97_recmask_io;
+	channel->lba = virt_to_bus(dmabuf->rawbuf);
+	channel->delta = compute_rate(dmabuf->rate);
 
-	return 0;
-}
+	channel->eso = dmabuf->dmasize >> sample_shift[dmabuf->fmt];
+	channel->eso -= 1;
 
-/* this function only update fmt field in trident_state, the hardware channel attribute
-   will be update in trident_play(rec)_setup() which will be called every time a new
-   sample is played(recorded) */
-static void set_fmt(struct trident_state *s, unsigned char mask, unsigned char data)
-{
-	s->fmt = (s->fmt & mask) | data;
-}
-
-/* the mode passed should be already shifted and masked */
-/* trident_play_setup: initialize channel for play back, mode specify the format of samples to
-   be played. 
-   default values: 
-*/
+	if (state->card->pci_id == PCI_DEVICE_ID_SI_7018) {
+		/* FIXME: channel attributes are configured by ioctls, but it is not implemented
+		   so just set to ZERO for the moment */
+		channel->attribute = 0;
+	} else {
+		channel->attribute = 0;
+	}
 
-static void trident_play_setup(struct trident_state *trident, int mode, u32 rate,
-			       void *buffer, int size)
-{
-	unsigned int LBA;
-	unsigned int Delta;
-	unsigned int ESO;
-	unsigned int CTRL;
-	unsigned int FMC_RVOL_CVOL;
-	unsigned int GVSEL;
-	unsigned int PAN;
-	unsigned int VOL;
-	unsigned int EC;
-
-	/* set Loop Begin Address */
-	LBA = virt_to_bus(buffer);
-	Delta = compute_rate(rate);
-
-	/* set ESO */
-	ESO = size;
-	if (mode & TRIDENT_FMT_16BIT)
-		ESO /= 2;
-	if (mode & TRIDENT_FMT_STEREO)
-		ESO /= 2;
-	ESO = ESO - 1;
-
-	/* loop mode enable */
-	CTRL = 0x00000001;
-	if (mode & TRIDENT_FMT_16BIT) {
+	channel->fm_vol = 0x0;
+	
+	channel->control = CHANNEL_LOOP;
+	if (dmabuf->fmt & TRIDENT_FMT_16BIT) {
 		/* 16-bits */
-		CTRL |= 0x00000008;
+		channel->control |= CHANNEL_16BITS;
 		/* signed */
-		CTRL |= 0x00000002;
+		channel->control |= CHANNEL_SIGNED;
 	}
-	if (mode & TRIDENT_FMT_STEREO)
+	if (dmabuf->fmt & TRIDENT_FMT_STEREO)
 		/* stereo */
-		CTRL |= 0x00000004;
-	
-	/* FIXME: some difference between 4D and 7018 in FMC_RVOL_CVOL */
-	/* right vol: mute, ledt vol: mute */
-	FMC_RVOL_CVOL = 0x0000ffff;
-	GVSEL = 1;
-	PAN = 0;
-	VOL = 0;
-	EC = 0;
-
-	trident_write_voice_regs(trident->card,
-				 trident->dma_dac.chan,
-				 LBA,
-				 0,	/* cso */
-				 ESO,
-				 Delta,
-				 0,	/* alpha */
-				 FMC_RVOL_CVOL,
-				 GVSEL,
-				 PAN,
-				 VOL,
-				 CTRL,
-				 EC);
-
-}
-
-/*
- *	Native record driver 
- */
-/* FIXME: Not exammed yet */
-/* again, passed mode is alrady shifted/masked */
-
-static void trident_rec_setup(struct trident_state *trident, int mode, u32 rate,
-			      void *buffer, int size)
-{
-	unsigned int LBA;
-	unsigned int Delta;
-	unsigned int ESO;
-	unsigned int CTRL;
-	unsigned int FMC_RVOL_CVOL;
-	unsigned int GVSEL;
-	unsigned int PAN;
-	unsigned int VOL;
-	unsigned int EC;
-	unsigned char bValue;
-	unsigned short wValue;
-	unsigned int dwValue;
-	unsigned short wRecCODECSamples;
-	unsigned int dwChanFlags;
-	struct trident_card *card = trident->card;
-
+		channel->control |= CHANNEL_STEREO;
 #ifdef DEBUG
-	printk("trident: trident_rec_setup called\n");
+	printk("trident: trident_rec_setup, LBA = 0x%08x, "
+	       "Delat = 0x%08x, ESO = 0x%08x, Control = 0x%08x\n",
+	       channel->lba, channel->delta, channel->eso, channel->control);
 #endif
-
-	// Enable AC-97 ADC (capture), disable capture interrupt
-	switch (card->pci_id) 
-	{
-	case PCI_DEVICE_ID_SI_7018:
-		/* for 7018, the ac97 is always in playback/record (duplex) mode */
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-		bValue = inb(TRID_REG(card, DX_ACR2_AC97_COM_STAT));
-		outb(bValue | 0x48, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		wValue = inw(TRID_REG(card, T4D_MISCINT));
-		outw(wValue | 0x1000, TRID_REG(card, T4D_MISCINT));
-		break;
-	}
-
-	// Initilize the channel and set channel Mode
-	outb(0, TRID_REG(card, LEGACY_DMAR15));
-
-	// Set DMA channel operation mode register
-	bValue = inb(TRID_REG(card, LEGACY_DMAR11)) & 0x03;
-	outb(bValue | 0x54, TRID_REG(card, LEGACY_DMAR11));
-
-	// Set channel buffer Address
-	LBA = virt_to_bus(buffer);
-	outl(LBA, TRID_REG(card, LEGACY_DMAR0));
-
-	/* set ESO */
-	ESO = size;
-
-	dwValue = inl(TRID_REG(card, LEGACY_DMAR4)) & 0xff000000;
-	dwValue |= (ESO - 1) & 0x0000ffff;
-	outl(dwValue, TRID_REG(card, LEGACY_DMAR4));
-
-	// Set channel sample rate , 4.12 format
-	dwValue = (((unsigned int) 48000L << 12) / (unsigned long) (rate));
-	outw((unsigned short) dwValue, TRID_REG(card, T4D_SBDELTA_DELTA_R));
-
-	// Set channel interrupt blk length
-	if (mode & TRIDENT_FMT_16BIT) {
-		wRecCODECSamples = (unsigned short) ((ESO >> 1) - 1);
-		dwChanFlags = 0xffffb000;
-	} else {
-		wRecCODECSamples = (unsigned short) (ESO - 1);
-		dwChanFlags = 0xffff1000;
-	}
-
-	dwValue = ((unsigned int) wRecCODECSamples) << 16;
-	dwValue |= (unsigned int) (wRecCODECSamples) & 0x0000ffff;
-	outl(dwValue, TRID_REG(card, T4D_SBBL_SBCL));
-
-	// Right now, set format and start to run capturing, 
-	// continuous run loop enable.
-	trident->bDMAStart = 0x19;	// 0001 1001b
-
-	if (mode & TRIDENT_FMT_16BIT)
-		trident->bDMAStart |= 0xa0;
-	if (mode & TRIDENT_FMT_STEREO)
-		trident->bDMAStart |= 0x40;
-
-	// Prepare capture intr channel
-
-	Delta = ((((unsigned int) rate) << 12) / ((unsigned long) (48000L)));
-
-	/* set Loop Back Address */
-	LBA = virt_to_bus(buffer);
-
-	/* set ESO */
-	ESO = size;
-	if (mode & TRIDENT_FMT_16BIT)
-		ESO /= 2;
-	if (mode & TRIDENT_FMT_STEREO)
-		ESO /= 2;
-
-	ESO = ESO - 1;
-	//snd_printk("trid: ESO = %d\n", ESO);
-
-	/* set ctrl mode
-	   CTRL default: 8-bit (unsigned) mono, loop mode enabled
-	 */
-	CTRL = 0x00000001;
-	if (mode & TRIDENT_FMT_16BIT)
-		CTRL |= 0x00000008;	// 16-bit data
-	/* XXX DO UNSIGNED XXX */
-	//if (!(mode & SND_PCM1_MODE_U))
-	//	CTRL |= 0x00000002;	// signed data
-	if (mode& TRIDENT_FMT_STEREO)
-		CTRL |= 0x00000004;	// stereo data
-
-	FMC_RVOL_CVOL = 0x0000ffff;
-	GVSEL = 1;
-	PAN = 0xff;
-	VOL = 0xff;
-	EC = 0;
-
-	trident_write_voice_regs(card,
-			     trident->dma_adc.chan,
-			     LBA,
-			     0,	/* cso */
-			     ESO,
-			     Delta,
-			     0,	/* alpha */
-			     FMC_RVOL_CVOL,
-			     GVSEL,
-			     PAN,
-			     VOL,
-			     CTRL,
-			     EC);
-
+	trident_write_voice_regs(state, 1);
 }
 
-/* get current playback pointer */
-__inline__ unsigned int get_dmaa(struct trident_state *trident)
+/* get current playback/recording dma buffer pointer (byte offset from LBA),
+   called with spinlock held! */
+extern __inline__ unsigned trident_get_dma_addr(struct trident_state *state, unsigned rec)
 {
+	struct dmabuf *dmabuf;
 	u32 cso;
-	u32 eso;
-#if 0
-	/* FIXME: does this mean that FULL duplex is not supported ? */
-	if (!(trident->enable & ADC_RUNNING))
+
+	if (rec)
+		dmabuf = &state->dma_adc;
+	else
+		dmabuf = &state->dma_dac;
+
+	if (!dmabuf->enable)
 		return 0;
-#endif
-	outb(trident->dma_dac.chan, TRID_REG(trident->card, T4D_LFO_GC_CIR));
 
-	switch (trident->card->pci_id) 
+	outb(dmabuf->channel->num, TRID_REG(state->card, T4D_LFO_GC_CIR));
+
+	switch (state->card->pci_id) 
 	{
 	case PCI_DEVICE_ID_SI_7018:
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
 		/* 16 bits ESO, CSO for 7018 and DX */
-		cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
-		eso = inw(TRID_REG(trident->card, CH_DX_ESO_DELTA + 2));
+		cso = inw(TRID_REG(state->card, CH_DX_CSO_ALPHA_FMS + 2));
 		break;
 	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
 		/* 24 bits ESO, CSO for NX */
-		cso =  inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
-		eso =  inl(TRID_REG(trident->card, CH_NX_DELTA_ESO)) & 0x00ffffff;
+		cso = inl(TRID_REG(state->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
 		break;
 	default:
 		return 0;
 	}
 
 #ifdef DEBUG
-	printk("trident: get_dmaa: chip reported channel: %d, cso = %d, eso = %d\n",
-	       trident->dma_dac.chan, cso, eso);
+	printk("trident: trident_get_dma_addr: chip reported channel: %d, cso = %d\n",
+	       dmabuf->channel->num, cso);
 #endif
 	/* ESO and CSO are in units of Samples, convert to byte offset */
-	if (cso > eso)
-		cso = eso;
-	if (trident->fmt & TRIDENT_FMT_16BIT)
-		cso *= 2;
-	if (trident->fmt & TRIDENT_FMT_STEREO)
-		cso *= 2;
-	return cso;
+	cso <<= sample_shift[dmabuf->fmt];
+
+	return (cso % dmabuf->dmasize);
 }
 
-/* get current recording pointer */
-extern __inline__ unsigned get_dmac(struct trident_state *trident)
+/* Stop recording (lock held) */
+extern __inline__ void __stop_adc(struct trident_state *state)
 {
-	u32 cso;
-#if 0
-	/* FIXME: does this mean that FULL duplex is not supported ? */
-	if (!(trident->enable & DAC_RUNNING))
-		return 0;
-#endif
-	outb(trident->dma_adc.chan, TRID_REG(trident->card, T4D_LFO_GC_CIR));
-
-	switch (trident->card->pci_id) 
-	{
-	default:
-	case PCI_DEVICE_ID_SI_7018:
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
-		/* 16 bits ESO, CSO for 7018 and DX */
-		cso = inw(TRID_REG(trident->card, CH_DX_CSO_ALPHA_FMS + 2));
-		break;
-	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
-		/* 24 bits ESO, CSO for NX */
-		cso = inl(TRID_REG(trident->card, CH_NX_DELTA_CSO)) & 0x00ffffff;
-		break;
-	}
+	struct dmabuf *dmabuf = &state->dma_adc;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
 
-#ifdef DEBUG
-	printk("(trident) get_dmac: chip reported cso = %d\n", cso);
-#endif
-	/* ESO and CSO are in units of Samples, convert to byte offset */
-	if (trident->fmt & TRIDENT_FMT_16BIT)
-		cso *= 2;
-	if (trident->fmt & TRIDENT_FMT_STEREO)
-		cso *= 2;
-	return cso;
+	dmabuf->enable &= ~DMA_RUNNING;
+	trident_stop_voice(card, chan_num);
+	trident_disable_voice_irq(card, chan_num);
 }
 
-/* Stop recording (lock held) */
-extern inline void __stop_adc(struct trident_state *s)
-{
-	struct trident_card *trident = s->card;
-#ifdef DEBUG
-	printk("(trident) stopping ADC\n");
-#endif
-	s->enable &= ~ADC_RUNNING;
-	trident_disable_voice_irq(trident, s->dma_adc.chan);
-	outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));
-	trident_disable_voice_irq(trident, s->dma_adc.chan);
-	trident_stop_voice(trident, s->dma_adc.chan);
-	ResetAinten(trident, s->dma_adc.chan);
-}	
+static void stop_adc(struct trident_state *state)
+{
+	struct trident_card *card = state->card;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->lock, flags);
+	__stop_adc(state);
+	spin_unlock_irqrestore(&card->lock, flags);
+}
 
-extern inline void stop_adc(struct trident_state *s)
+static void start_adc(struct trident_state *state)
 {
+	struct dmabuf *dmabuf = &state->dma_adc;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
 	unsigned long flags;
-	struct trident_card *trident = s->card;
 
-	spin_lock_irqsave(&trident->lock, flags);
-	__stop_adc(s);
-	spin_unlock_irqrestore(&trident->lock, flags);
-}	
+	spin_lock_irqsave(&card->lock, flags);
+	if ((dmabuf->mapped || 
+	     dmabuf->count < (signed)(dmabuf->dmasize - 2*dmabuf->fragsize))
+	    && dmabuf->ready) {
+		dmabuf->enable |= DMA_RUNNING;
+		trident_enable_voice_irq(card, chan_num);
+		trident_start_voice(card, chan_num);
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+}
 
 /* stop playback (lock held) */
-extern inline void __stop_dac(struct trident_state *state)
+extern __inline__ void __stop_dac(struct trident_state *state)
 {
-	struct trident_card *trident = state->card;
-	trident_stop_voice(trident, state->dma_dac.chan);
-	trident_disable_voice_irq(trident, state->dma_dac.chan);
-	state->enable &= ~DAC_RUNNING;
-}	
+	struct dmabuf *dmabuf = &state->dma_dac;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
 
-extern inline void stop_dac(struct trident_state *state)
+	dmabuf->enable &= ~DMA_RUNNING;
+	trident_stop_voice(card, chan_num);
+	trident_disable_voice_irq(card, chan_num);
+}
+
+static void stop_dac(struct trident_state *state)
 {
-	struct trident_card *trident = state->card;
+	struct trident_card *card = state->card;
 	unsigned long flags;
 
-	spin_lock_irqsave(&trident->lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
 	__stop_dac(state);
-	spin_unlock_irqrestore(&trident->lock, flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 }	
 
 static void start_dac(struct trident_state *state)
 {
-	unsigned long flags;
-	struct trident_card *trident = state->card;
-
-	spin_lock_irqsave(&state->card->lock, flags);
-	if ((state->dma_dac.mapped || state->dma_dac.count > 0) && state->dma_dac.ready) {
-		state->enable |= DAC_RUNNING;
-		trident_enable_voice_irq(trident, state->dma_dac.chan);
-		trident_start_voice(trident, state->dma_dac.chan);
-	}
-	spin_unlock_irqrestore(&state->card->lock, flags);
-}	
-
-static void start_adc(struct trident_state *s)
-{
+	struct dmabuf *dmabuf = &state->dma_dac;
+	unsigned int chan_num = dmabuf->channel->num;
+	struct trident_card *card = state->card;
 	unsigned long flags;
 
-	spin_lock_irqsave(&s->card->lock, flags);
-	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
-	    && s->dma_adc.ready) {
-		s->enable |= ADC_RUNNING;
-		trident_enable_voice_irq(s->card, s->dma_adc.chan);
-		outb(s->bDMAStart, TRID_REG(s->card, T4D_SBCTRL_SBE2R_SBDD));
-		trident_start_voice(s->card, s->dma_adc.chan);
-#ifdef DEBUG
-		printk("(trident) starting ADC\n");
-#endif	
+	spin_lock_irqsave(&card->lock, flags);
+	if ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) {
+		dmabuf->enable |= DMA_RUNNING;
+		trident_enable_voice_irq(card, chan_num);
+		trident_start_voice(card, chan_num);
 	}
-	spin_unlock_irqrestore(&s->card->lock, flags);
-}	
+	spin_unlock_irqrestore(&card->lock, flags);
+}
 
 #define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
 #define DMABUF_MINORDER 1
@@ -1623,10 +823,16 @@
 /* allocate DMA buffer, playback and recording buffer should be allocated seperately */
 static int alloc_dmabuf(struct trident_state *state, unsigned rec)
 {
+	struct dmabuf *dmabuf;
 	void *rawbuf;
 	int order;
 	unsigned long map, mapend;
 
+	if (rec)
+		dmabuf  = &state->dma_adc;
+	else
+		dmabuf  = &state->dma_dac;
+
 	/* alloc as big a chunk as we can, FIXME: is this necessary ?? */
 	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
 		if ((rawbuf = (void *)__get_free_pages(GFP_KERNEL, order)))
@@ -1634,7 +840,7 @@
 	if (!rawbuf)
 		return -ENOMEM;
 #ifdef DEBUG
-	printk("trident: allocated %ld (%d) bytes at %p\n",
+	printk("trident: allocated %ld (order = %d) bytes at %p\n",
 	       PAGE_SIZE << order, order, rawbuf);
 #endif
 
@@ -1648,17 +854,10 @@
 		return -ENOMEM;
 	}
 
-	if (rec) {
-		state->dma_adc.ready = state->dma_adc.mapped = 0;
-		state->dma_adc.rawbuf = rawbuf;
-		state->dma_adc.buforder = order;
-	}
-	else {
-		state->dma_dac.ready = state->dma_dac.mapped = 0;
-		state->dma_dac.rawbuf = rawbuf;
-		state->dma_dac.buforder = order;
-	}
-
+	dmabuf->ready  = dmabuf->mapped = 0;
+	dmabuf->rawbuf = rawbuf;
+	dmabuf->buforder = order;
+	
 	/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
 	mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
 	for (map = MAP_NR(rawbuf); map <= mapend; map++)
@@ -1668,180 +867,237 @@
 }
 
 /* free DMA buffer */
-static void dealloc_dmabuf(struct dmabuf *db)
+static void dealloc_dmabuf(struct dmabuf *dmabuf)
 {
 	unsigned long map, mapend;
 
-	if (db->rawbuf) {
+	if (dmabuf->rawbuf) {
 		/* undo marking the pages as reserved */
-		mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+		mapend = MAP_NR(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
+		for (map = MAP_NR(dmabuf->rawbuf); map <= mapend; map++)
 			clear_bit(PG_reserved, &mem_map[map].flags);	
-		free_pages((unsigned long)db->rawbuf, db->buforder);
+		free_pages((unsigned long)dmabuf->rawbuf, dmabuf->buforder);
 	}
-	db->rawbuf = NULL;
-	db->mapped = db->ready = 0;
+	dmabuf->rawbuf = NULL;
+	dmabuf->mapped = dmabuf->ready = 0;
 }
 
 static int prog_dmabuf(struct trident_state *state, unsigned rec)
 {
-	struct dmabuf *db = rec ? &state->dma_adc : &state->dma_dac;
-	unsigned rate = rec ? state->rateadc : state->ratedac;
+	struct dmabuf *dmabuf;
 	unsigned bytepersec;
-	unsigned bufs;
-	unsigned char fmt;
+	unsigned bufsize;
 	unsigned long flags;
 	int ret;
 
+	if (rec)
+		dmabuf = &state->dma_adc;
+	else
+		dmabuf = &state->dma_dac;
+
 	spin_lock_irqsave(&state->card->lock, flags);
-	fmt = state->fmt;
-	if (rec) {
-		state->enable &= ~TRIDENT_ENABLE_RE;
-		fmt >>= TRIDENT_ADC_SHIFT;
-	} else {
-		state->enable &= ~TRIDENT_ENABLE_PE;
-		fmt >>= TRIDENT_DAC_SHIFT;
-	}
+	dmabuf->hwptr  = dmabuf->swptr = dmabuf->total_bytes = 0;
+	dmabuf->count  = dmabuf->error = dmabuf->endcleared  = 0;
 	spin_unlock_irqrestore(&state->card->lock, flags);
 
-	fmt &= TRIDENT_FMT_MASK;
-
-	db->hwptr = db->swptr = db->total_bytes = 0;
-	db->count = db->error = db->endcleared  = 0;
-
 	/* allocate DMA buffer if not allocated yet */
-	if (!db->rawbuf)
+	if (!dmabuf->rawbuf)
 		if ((ret = alloc_dmabuf(state, rec)))
 			return ret;
 
-	bytepersec = rate << sample_shift[fmt];
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytepersec)
-			db->fragshift = ld2(bytepersec/1000);
+	/* FIXME: figure out all this OSS fragment stuff */
+	bytepersec = dmabuf->rate << sample_shift[dmabuf->fmt];
+	bufsize = PAGE_SIZE << dmabuf->buforder;
+	if (dmabuf->ossfragshift) {
+		if ((1000 << dmabuf->ossfragshift) < bytepersec)
+			dmabuf->fragshift = ld2(bytepersec/1000);
 		else
-			db->fragshift = db->ossfragshift;
+			dmabuf->fragshift = dmabuf->ossfragshift;
 	} else {
 		/* lets hand out reasonable big ass buffers by default */
-		db->fragshift = (db->buforder + PAGE_SHIFT -2);
+		dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT -2);
 	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-	db->fragsamples = db->fragsize >> sample_shift[fmt];
-	db->dmasize = db->numfrag << db->fragshift;
+	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+	while (dmabuf->numfrag < 4 && dmabuf->fragshift > 3) {
+		dmabuf->fragshift--;
+		dmabuf->numfrag = bufsize >> dmabuf->fragshift;
+	}
+	dmabuf->fragsize = 1 << dmabuf->fragshift;
+	if (dmabuf->ossmaxfrags >= 4 && dmabuf->ossmaxfrags < dmabuf->numfrag)
+		dmabuf->numfrag = dmabuf->ossmaxfrags;
+	dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];
+	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
 
-	memset(db->rawbuf, (fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80, db->dmasize);
+	memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80,
+	       dmabuf->dmasize);
 
 	spin_lock_irqsave(&state->card->lock, flags);
 	if (rec) {
-		trident_rec_setup(state, fmt, state->rateadc, 
-				  db->rawbuf, db->numfrag << db->fragshift);
+		trident_rec_setup(state);
 	} else {
-		trident_play_setup(state, fmt, state->ratedac, 
-				   db->rawbuf, db->numfrag << db->fragshift);
+		trident_play_setup(state);
 	}
 	spin_unlock_irqrestore(&state->card->lock, flags);
 
 	/* set the ready flag for the dma buffer */
-	db->ready = 1;
+	dmabuf->ready = 1;
 
 #ifdef DEBUG
 	printk("trident: prog_dmabuf, sample rate = %d, format = %d, numfrag = %d, "
 	       "fragsize = %d dmasize = %d\n",
-	       rate, fmt, db->numfrag, db->fragsize, db->dmasize);
+	       dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
+	       dmabuf->fragsize, dmabuf->dmasize);
 #endif
 
 	return 0;
 }
 
-extern __inline__ void clear_advance(struct trident_state *s)
+/* we are doing quantum mechanics here, the buffer can only be empty, half or full filled i.e.
+   |------------|------------|   or   |xxxxxxxxxxxx|------------|   or   |xxxxxxxxxxxx|xxxxxxxxxxxx|
+   but we almost always get this
+   |xxxxxx------|------------|   or   |xxxxxxxxxxxx|xxxxx-------|
+   so we have to clear the tail space to "silence"
+   |xxxxxx000000|------------|   or   |xxxxxxxxxxxx|xxxxxx000000|
+*/
+static void trident_clear_tail(struct trident_state *state)
+{
+	struct dmabuf *dmabuf = &state->dma_dac;
+	unsigned swptr;
+	unsigned char silence = (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80;
+	unsigned int len;
+	unsigned long flags;
+
+	spin_lock_irqsave(&state->card->lock, flags);
+	swptr = dmabuf->swptr;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	if (swptr == 0 || swptr == dmabuf->dmasize / 2 || swptr == dmabuf->dmasize)
+		return;
+
+
+	if (swptr < dmabuf->dmasize/2)
+		len = dmabuf->dmasize/2 - swptr;
+	else
+		len = dmabuf->dmasize - swptr;
+
+	memset(dmabuf->rawbuf + swptr, silence, len);
+
+	spin_lock_irqsave(&state->card->lock, flags);	
+	dmabuf->swptr += len;
+	dmabuf->count += len;
+	spin_unlock_irqrestore(&state->card->lock, flags);
+
+	/* restart the dma machine in case it is halted */
+	start_dac(state);
+}
+
+static int drain_dac(struct trident_state *state, int nonblock)
 {
-	unsigned char c = ((s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_16BIT) ? 0 : 0x80;
-	unsigned char *buf = s->dma_dac.rawbuf;
-	unsigned bsize = s->dma_dac.dmasize;
-	unsigned bptr = s->dma_dac.swptr;
-	unsigned len = s->dma_dac.fragsize;
-
-	if (bptr + len > bsize) {
-		unsigned x = bsize - bptr;
-		memset(buf + bptr, c, x);
-		/* account for wrapping? */
-		bptr = 0;
-		len -= x;
+	DECLARE_WAITQUEUE(wait, current);
+	struct dmabuf *dmabuf = &state->dma_dac;
+	unsigned long flags;
+	unsigned long tmo;
+	int count;
+
+	if (dmabuf->mapped || !dmabuf->ready)
+		return 0;
+
+	add_wait_queue(&dmabuf->wait, &wait);
+	for (;;) {
+		/* It seems that we have to set the current state to TASK_INTERRUPTIBLE
+		   every time to make the process really go to sleep */
+		current->state = TASK_INTERRUPTIBLE;
+
+		spin_lock_irqsave(&state->card->lock, flags);
+		count = dmabuf->count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+
+		if (count <= 0)
+			break;
+
+		if (signal_pending(current))
+			break;
+
+		if (nonblock) {
+			remove_wait_queue(&dmabuf->wait, &wait);
+			current->state = TASK_RUNNING;
+			return -EBUSY;
+		}
+
+		/* No matter how much data left in the buffer, we have to wait untill
+		   CSO == ESO/2 or CSO == ESO when address engine interrupts */
+		tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
+		tmo >>= sample_shift[dmabuf->fmt];
+		if (!schedule_timeout(tmo ? tmo : 1) && tmo){
+			printk(KERN_ERR "trident: drain_dac, dma timeout?\n");
+			break;
+		}
 	}
-	memset(buf + bptr, c, len);
+	remove_wait_queue(&dmabuf->wait, &wait);
+	current->state = TASK_RUNNING;
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+
+	return 0;
 }
 
 /* call with spinlock held! */
-static void trident_update_ptr(struct trident_state *s)
+static void trident_update_ptr(struct trident_state *state)
 {
+	struct dmabuf *dmabuf;
 	unsigned hwptr;
 	int diff;
 
 	/* update ADC pointer */
-	if (s->dma_adc.ready) {
-		hwptr = get_dmac(s) % s->dma_adc.dmasize;
-		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % 
-			s->dma_adc.dmasize;
-		s->dma_adc.hwptr = hwptr;
-		s->dma_adc.total_bytes += diff;
-		s->dma_adc.count += diff;
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
-			wake_up(&s->dma_adc.wait);
-		if (!s->dma_adc.mapped) {
-			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-				s->enable &= ~TRIDENT_ENABLE_RE;
-				__stop_adc(s); 
-				s->dma_adc.error++;
+	if (state->dma_adc.ready) {
+		dmabuf = &state->dma_adc;
+		hwptr = trident_get_dma_addr(state, 1);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+		dmabuf->count += diff;
+
+		if (dmabuf->count >= (signed)dmabuf->fragsize)
+			wake_up(&dmabuf->wait);
+		if (!dmabuf->mapped) {
+			if (dmabuf->count > (signed)(dmabuf->dmasize - ((3 * dmabuf->fragsize) >> 1))) {
+				__stop_adc(state); 
+				dmabuf->error++;
 			}
 		}
 	}
 
 	/* update DAC pointer */
-	if (s->dma_dac.ready) {
-		hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
-		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % 
-			s->dma_dac.dmasize;
-		s->dma_dac.hwptr = hwptr;
-		s->dma_dac.total_bytes += diff;
-		if (s->dma_dac.mapped) {
-			s->dma_dac.count += diff;
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
-				wake_up(&s->dma_dac.wait);
-		} 
+	if (state->dma_dac.ready) {
+		dmabuf = &state->dma_dac;
+		hwptr = trident_get_dma_addr(state, 0);
+		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
+
+		dmabuf->hwptr = hwptr;
+		dmabuf->total_bytes += diff;
+
+		if (dmabuf->mapped) {
+			dmabuf->count += diff;
+			if (dmabuf->count >= (signed)dmabuf->fragsize) 
+				wake_up(&dmabuf->wait);
+		}
 		else {
-			s->dma_dac.count -= diff;
-			if (s->dma_dac.count <= 0) {
-				s->enable &= ~TRIDENT_ENABLE_PE;
-				/* Lock already held */
-				__stop_dac(s);
-				/* brute force everyone back in sync, sigh */
-				s->dma_dac.count = 0; 
-				s->dma_dac.swptr = 0; 
-				s->dma_dac.hwptr = 0; 
-				s->dma_dac.error++;
-			} 
-			else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && 
-				 !s->dma_dac.endcleared) {
-				clear_advance(s);
-				s->dma_dac.endcleared = 1;
+			dmabuf->count -= diff;
+			if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
+				/* buffer underrun or buffer overrun, we have no way to recover
+				   it here, just stop the machine and let the process force hwptr
+				   and swptr to sync */
+				__stop_dac(state);
+				dmabuf->error++;
 			}
-
-			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) 
-				wake_up(&s->dma_dac.wait);
+			/* since dma machine only interrupts at ESO and ESO/2, we sure have at 
+			   least half of dma buffer free, so wake up the process unconditionally */
+			wake_up(&dmabuf->wait);
 		}
 	}
 }
 
-/*
- *	Trident interrupt handlers.
- */
 static void trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct trident_state *state;
@@ -1858,19 +1114,17 @@
 
 	if (event & ADDRESS_IRQ) {
 		/* Update the pointers for all channels we are running. */
-		/* FIXME: improve interrupt latency !!! */
-		for (i = 0; i < NR_DSPS; i++) {
-			state = card->channels[i];
+		/* FIXME: should read interrupt status only once */
+		for (i = 0; i < NR_HW_CH; i++) {
 			if (trident_check_channel_interrupt(card, 63 - i)) {
 				trident_ack_channel_interrupt(card, 63 - i);
-				if (state != NULL)
+				if ((state = card->states[i]) != NULL) {
 					trident_update_ptr(state);
-				else {
-					/* Spurious ? */
-					printk("trident: spurious channel irq %d.\n", 
+				} else {
+					printk("trident: spurious channel irq %d.\n",
 					       63 - i);
 					trident_stop_voice(card, i);
-					trident_disable_voice_irq(card, i);
+					trident_disable_voice_irq(card, i);	
 				}
 			}
 		}
@@ -1886,254 +1140,29 @@
 	spin_unlock(&card->lock);
 }
 
-static void set_mixer(struct trident_card *card,unsigned int mixer, unsigned int val ) 
-{
-	unsigned int left,right;
-
-	/* cleanse input a little */
-	right = ((val >> 8)  & 0xff) ;
-	left = (val  & 0xff) ;
-
-	if (right > 100) right = 100;
-	if (left > 100) left = 100;
-
-	card->mix.mixer_state[mixer] = (right << 8) | left;
-	card->mix.write_mixer(card, mixer, left, right);
-}
-
-static int mixer_ioctl(struct trident_card *card, unsigned int cmd, unsigned long arg)
-{
-	unsigned long flags;
-	int i, val = 0;
-
-	VALIDATE_CARD(card);
-	if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		strncpy(info.id, card->pci_info->name, sizeof(info.id));
-		strncpy(info.name, card->pci_info->name, sizeof(info.name));
-		info.modify_counter = card->mix.modcnt;
-		if (copy_to_user((void *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		strncpy(info.id, card->pci_info->name, sizeof(info.id));
-		strncpy(info.name, card->pci_info->name, sizeof(info.name));
-		if (copy_to_user((void *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-		return -EINVAL;
-
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, (int *)arg);
-
-	if (_IOC_DIR(cmd) == _IOC_READ) {
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* give them the current record source */
-			if (!card->mix.recmask_io) {
-				val = 0;
-			} else {
-				spin_lock_irqsave(&card->lock, flags);
-				val = card->mix.recmask_io(card,1,0);
-				spin_unlock_irqrestore(&card->lock, flags);
-			}
-			break;
-
-		case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
-			val = card->mix.supported_mixers;
-			break;
-
-		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			val = card->mix.record_sources;
-			break;
-
-		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			val = card->mix.stereo_mixers;
-			break;
-
-		case SOUND_MIXER_CAPS:
-			val = SOUND_CAP_EXCL_INPUT;
-			break;
-
-		default: /* read a specific mixer */
-			i = _IOC_NR(cmd);
-
-			if (!supported_mixer(card,i)) 
-				return -EINVAL;
-
-			/* do we ever want to touch the hardware? */
-			/* spin_lock_irqsave(&s->lock, flags);
-			val = card->mix.read_mixer(card,i);
-			spin_unlock_irqrestore(&s->lock, flags);*/
-
-			val = card->mix.mixer_state[i];
-			/* printk("returned 0x%x for mixer %d\n",val,i);*/
-			break;
-		}
-		return put_user(val,(int *)arg);
-	}
-
-	if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
-		card->mix.modcnt++;
-		get_user_ret(val, (int *)arg, -EFAULT);
-
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			if (!card->mix.recmask_io) return -EINVAL;
-			if (!(val &= card->mix.record_sources)) return -EINVAL;
-
-			spin_lock_irqsave(&card->lock, flags);
-			card->mix.recmask_io(card, 0, val);
-			spin_unlock_irqrestore(&card->lock, flags);
-
-			return 0;
-		default: /* write a specific mixer */
-			i = _IOC_NR(cmd);
-
-			if (!supported_mixer(card, i)) 
-				return -EINVAL;
-
-			spin_lock_irqsave(&card->lock, flags);
-			set_mixer(card, i, val);
-			spin_unlock_irqrestore(&card->lock, flags);
-
-			return 0;
-		}
-	}
-	return -EINVAL;
-}
-
-static int trident_open_mixdev(struct inode *inode, struct file *file)
-{
-	int minor = MINOR(inode->i_rdev);
-	struct trident_card *card = devs;
-
-	while (card && card->dev_mixer != minor)
-		card = card->next;
-	if (!card)
-		return -ENODEV;
-
-	file->private_data = card;
-
-	//FIXME put back in
-	//MOD_INC_USE_COUNT;
-	return 0;
-}
-
-static int trident_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct trident_card *card = (struct trident_card *)file->private_data;
-
-	VALIDATE_CARD(card);
-	
-	//FIXME put back in
-	//MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, 
-				unsigned long arg)
-{
-	struct trident_card *card = (struct trident_card *)file->private_data;
-
-	VALIDATE_CARD(card);
-	return mixer_ioctl(card, cmd, arg);
-}
-
 static loff_t trident_llseek(struct file *file, loff_t offset, int origin)
 {
 	return -ESPIPE;
 }
 
-static /*const*/ struct file_operations trident_mixer_fops = {
-	&trident_llseek,
-	NULL,  /* read */
-	NULL,  /* write */
-	NULL,  /* readdir */
-	NULL,  /* poll */
-	&trident_ioctl_mixdev,
-	NULL,  /* mmap */
-	&trident_open_mixdev,
-	NULL,	/* flush */
-	&trident_release_mixdev,
-	NULL,  /* fsync */
-	NULL,  /* fasync */
-	NULL,  /* lock */
-};
-
-/* drain the DAC buffer
-   FIXME: This function will block (forever ??) when using
-   XMMS Qsound plugin and direct cat sample.wav > /dev/dsp
-   This behavior is when drain_dac is called by trident_release. */
-static int drain_dac(struct trident_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count;
-	signed long tmo;
-
-	if (s->dma_dac.mapped || !s->dma_dac.ready)
-		return 0;
-
-	current->state = TASK_INTERRUPTIBLE;
-	add_wait_queue(&s->dma_dac.wait, &wait);
-	for (;;) {
-		spin_lock_irqsave(&s->card->lock, flags);
-		count = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->card->lock, flags);
-
-		if (count <= 0)
-			break;
-
-		if (signal_pending(current))
-			break;
-
-		if (nonblock) {
-			remove_wait_queue(&s->dma_dac.wait, &wait);
-			current->state = TASK_RUNNING;
-			return -EBUSY;
-		}
-		
-		tmo = (count * HZ) / s->ratedac;
-		tmo >>= sample_shift[(s->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK];
-
-		/* XXX this is just broken.  someone is waking us up alot, 
-		   or schedule_timeout is broken.
-		   or something.  who cares. - zach */
-		if (!schedule_timeout(tmo ? tmo : 1) && tmo)
-			printk(KERN_ERR "trident: drain_dac, "
-			       "dma timed out? jiffies = %ld\n",
-			       jiffies);
-	}
-	remove_wait_queue(&s->dma_dac.wait, &wait);
-	current->state = TASK_RUNNING;
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-
-	return 0;
-}
-
 /* in this loop, dma_adc.count signifies the amount of data thats waiting
    to be copied to the user's buffer.  it is filled by the interrupt
    handler and drained by this loop. */
 static ssize_t trident_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dma_dac;
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
 	int cnt;
-	
+
 	VALIDATE_STATE(state);
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
-	if (state->dma_adc.mapped)
+	if (dmabuf->mapped)
 		return -ENXIO;
-	if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
 		return ret;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
@@ -2141,12 +1170,10 @@
 
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
-		/* remember, all these things are expressed in bytes to be
-		   sent to the user.. hence the evil / 2 down below */
-		swptr = state->dma_adc.swptr;
-		cnt = state->dma_adc.dmasize - swptr;
-		if (state->dma_adc.count < cnt)
-			cnt = state->dma_adc.count;
+		swptr = dmabuf->swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if (dmabuf->count < cnt)
+			cnt = dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		if (cnt > count)
@@ -2158,20 +1185,17 @@
 				ret = ret ? ret : -EAGAIN;
 				return ret;
 			}
-			if (!interruptible_sleep_on_timeout(&state->dma_adc.wait, HZ)) {
-				printk(KERN_DEBUG "(trident) read: chip lockup? "
+			if (!interruptible_sleep_on_timeout(&dmabuf->wait, HZ)) {
+				printk(KERN_ERR
+				       "(trident) read: chip lockup? "
 				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       state->dma_adc.dmasize,
-				       state->dma_adc.fragsize,
-				       state->dma_adc.count,
-				       state->dma_adc.hwptr,
-				       state->dma_adc.swptr);
+				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				       dmabuf->hwptr, dmabuf->swptr);
 				stop_adc(state);
-
 				spin_lock_irqsave(&state->card->lock, flags);
-				state->dma_adc.count = 0;
-				state->dma_adc.hwptr = 0;
-				state->dma_adc.swptr = 0;
+				dmabuf->count = 0;
+				dmabuf->hwptr = 0;
+				dmabuf->swptr = 0;
 				spin_unlock_irqrestore(&state->card->lock, flags);
 			}
 			if (signal_pending(current)) {
@@ -2180,17 +1204,19 @@
 			}
 			continue;
 		}
-	
-		if (copy_to_user(buffer, state->dma_adc.rawbuf + swptr, cnt)) {
+
+		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
 			ret = ret ? ret : -EFAULT;
 			return ret;
 		}
 
-		swptr = (swptr + cnt) % state->dma_adc.dmasize;
+		swptr = (swptr + cnt) % dmabuf->dmasize;
+
 		spin_lock_irqsave(&state->card->lock, flags);
-		state->dma_adc.swptr = swptr;
-		state->dma_adc.count -= cnt;
+		dmabuf->swptr = swptr;
+		dmabuf->count -= cnt;
 		spin_unlock_irqrestore(&state->card->lock, flags);
+
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
@@ -2203,11 +1229,11 @@
 static ssize_t trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf = &state->dma_dac;
 	ssize_t ret;
 	unsigned long flags;
 	unsigned swptr;
 	int cnt;
-	int mode = (state->fmt >> TRIDENT_DAC_SHIFT) & TRIDENT_FMT_MASK;
 
 #ifdef DEBUG
 	printk("trident: trident_write called, count = %d\n", count);
@@ -2216,9 +1242,9 @@
 	VALIDATE_STATE(state);
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
-	if (state->dma_dac.mapped)
+	if (dmabuf->mapped)
 		return -ENXIO;
-	if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
+	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
@@ -2226,41 +1252,47 @@
 
 	while (count > 0) {
 		spin_lock_irqsave(&state->card->lock, flags);
-		if (state->dma_dac.count < 0) {
-			state->dma_dac.count = 0;
-			state->dma_dac.swptr = state->dma_dac.hwptr;
-		}
-		swptr = state->dma_dac.swptr;
-		cnt = state->dma_dac.dmasize - swptr;
-		if (state->dma_dac.count + cnt > state->dma_dac.dmasize)
-			cnt = state->dma_dac.dmasize - state->dma_dac.count;
+		if (dmabuf->count < 0) {
+			/* buffer underrun, we are recovering from sleep_on_timeout,
+			   resync hwptr and swptr */
+			dmabuf->count = 0;
+			dmabuf->swptr = dmabuf->hwptr;
+		}
+		swptr = dmabuf->swptr;
+		cnt = dmabuf->dmasize - swptr;
+		if (dmabuf->count + cnt > dmabuf->dmasize)
+			cnt = dmabuf->dmasize - dmabuf->count;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			/* buffer is full, wait for it to be played */
+			unsigned long tmo;
+			/* buffer is full, start the dma machine and wait for data to be played */
 			start_dac(state);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
 				return ret;
 			}
-			if (!interruptible_sleep_on_timeout(&state->dma_dac.wait, HZ)) {
-				printk(KERN_ERR 
-				       "trident: write: chip lockup? "
-				       "dmasz %u fragsz %u count %i "
-				       "hwptr %u swptr %u\n", 
-				       state->dma_dac.dmasize, 
-				       state->dma_dac.fragsize, 
-				       state->dma_dac.count, 
-				       state->dma_dac.hwptr, 
-				       state->dma_dac.swptr);
-				stop_dac(state);
-				spin_lock_irqsave(&state->card->lock, flags);
-				state->dma_dac.count = 0;
-				state->dma_dac.hwptr = 0;
-				state->dma_dac.swptr = 0;
-				spin_unlock_irqrestore(&state->card->lock, flags);
+			/* No matter how much data left in the buffer, we have to wait untill
+			   CSO == ESO/2 or CSO == ESO when address engine interrupts */
+			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
+			tmo >>= sample_shift[dmabuf->fmt];
+			/* There are two situations when sleep_on_timeout returns, one is when the
+			   interrupt is serviced correctly and the process is waked up by ISR ON TIME.
+			   Another is when timeout is expired, which means that either interrupt is NOT
+			   serviced correctly (pending interrupt) or it is TOO LATE for the process to 
+			   be scheduled to run (scheduler latency) which results in a (potential) buffer
+			   underrun. And worse, there is NOTHING we can do to prevent it. */
+			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
+#ifdef DEBUG
+				printk(KERN_ERR "trident: schedule timeout, "
+				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
+				       dmabuf->hwptr, dmabuf->swptr);
+#endif
+				/* a buffer underrun, we delay the recovery untill next time the
+				   while loop begin and we REALLY have data to play */
 			}
 			if (signal_pending(current)) {
 				if (!ret) ret = -ERESTARTSYS;
@@ -2268,18 +1300,17 @@
 			}
 			continue;
 		}
-		if (copy_from_user(state->dma_dac.rawbuf + swptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
+		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
+			if (!ret) ret = -EFAULT;
 			return ret;
 		}
 
-		swptr = (swptr + cnt) % state->dma_dac.dmasize;
+		swptr = (swptr + cnt) % dmabuf->dmasize;
 
 		spin_lock_irqsave(&state->card->lock, flags);
-		state->dma_dac.swptr = swptr;
-		state->dma_dac.count += cnt;
-		state->dma_dac.endcleared = 0;
+		dmabuf->swptr = swptr;
+		dmabuf->count += cnt;
+		dmabuf->endcleared = 0;
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
 		count -= cnt;
@@ -2304,7 +1335,6 @@
 
 	spin_lock_irqsave(&s->card->lock, flags);
 	trident_update_ptr(s);
-
 	if (file->f_mode & FMODE_READ) {
 		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
 			mask |= POLLIN | POLLRDNORM;
@@ -2319,56 +1349,56 @@
 		}
 	}
 	spin_unlock_irqrestore(&s->card->lock, flags);
+
 	return mask;
 }
 
-/* this needs to be fixed to deal with the dual apus/buffers */
-#if 0
 static int trident_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct trident_state *s = (struct trident_state *)file->private_data;
-	struct dmabuf *db;
+	struct trident_state *state = (struct trident_state *)file->private_data;
+	struct dmabuf *dmabuf;
 	int ret;
 	unsigned long size;
 
-	VALIDATE_STATE(s);
+	VALIDATE_STATE(state);
 	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf(s, 0)) != 0)
+		if ((ret = prog_dmabuf(state, 0)) != 0)
 			return ret;
-		db = &s->dma_dac;
+		dmabuf = &state->dma_dac;
 	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf(s, 1)) != 0)
+		if ((ret = prog_dmabuf(state, 1)) != 0)
 			return ret;
-		db = &s->dma_adc;
+		dmabuf = &state->dma_adc;
 	} else 
 		return -EINVAL;
-	if (vma->vm_offset != 0)
+
+	if (vma->vm_pgoff != 0)
 		return -EINVAL;
 	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder))
+	if (size > (PAGE_SIZE << dmabuf->buforder))
 		return -EINVAL;
-	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
+			     size, vma->vm_page_prot))
 		return -EAGAIN;
-	db->mapped = 1;
+	dmabuf->mapped = 1;
+
 	return 0;
 }
-#endif
 
 static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct trident_state *s = (struct trident_state *)file->private_data;
+	struct trident_state *state = (struct trident_state *)file->private_data;
 	unsigned long flags;
 	audio_buf_info abinfo;
 	count_info cinfo;
 	int val, mapped, ret;
-	unsigned char fmtm, fmtd;
 
-	VALIDATE_STATE(s);
-	mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+	VALIDATE_STATE(state);
+	mapped = ((file->f_mode & FMODE_WRITE) && state->dma_dac.mapped) ||
+		((file->f_mode & FMODE_READ) && state->dma_adc.mapped);
 #ifdef DEBUG
-	printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",_IOC_NR(cmd), 
-	       arg ? *(int *)arg : 0);
+	printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",
+	       _IOC_NR(cmd), arg ? *(int *)arg : 0);
 #endif
 
 	switch (cmd) 
@@ -2378,189 +1408,218 @@
 
 	case SNDCTL_DSP_RESET:
 		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
+			stop_dac(state);
 			synchronize_irq();
-			s->dma_dac.swptr = s->dma_dac.hwptr = 0;
-			s->dma_dac.count = s->dma_dac.total_bytes = 0;
+			state->dma_dac.ready = 0;
+			state->dma_dac.swptr = state->dma_dac.hwptr = 0;
+			state->dma_dac.count = state->dma_dac.total_bytes = 0;
 		}
 		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
+			stop_adc(state);
 			synchronize_irq();
-			s->dma_adc.swptr = s->dma_adc.hwptr = 0;
-			s->dma_adc.count = s->dma_adc.total_bytes = 0;
+			state->dma_adc.ready = 0;
+			state->dma_adc.swptr = state->dma_adc.hwptr = 0;
+			state->dma_adc.count = state->dma_adc.total_bytes = 0;
 		}
 		return 0;
 
 	case SNDCTL_DSP_SYNC:
 		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, file->f_flags & O_NONBLOCK);
+			return drain_dac(state, file->f_flags & O_NONBLOCK);
 		return 0;
 
-	case SNDCTL_DSP_SPEED:
+	case SNDCTL_DSP_SPEED: /* set smaple rate */
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val >= 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				trident_set_adc_rate(s, val, 1);
-			}
 			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				trident_set_dac_rate(s, val, 1);
+				stop_dac(state);
+				state->dma_dac.ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				trident_set_dac_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
+			}
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				state->dma_adc.ready = 0;
+				spin_lock_irqsave(&state->card->lock, flags);
+				trident_set_adc_rate(state, val);
+				spin_unlock_irqrestore(&state->card->lock, flags);
 			}
 		}
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac,
+		return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
+				state->dma_dac.rate,
 				(int *)arg);
 
-	case SNDCTL_DSP_STEREO:
+	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
 		get_user_ret(val, (int *)arg, -EFAULT);
-		fmtd = 0;
-		fmtm = ~0;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ready = 0;
+		if (file->f_mode & FMODE_WRITE) {
+			stop_dac(state);
+			state->dma_dac.ready = 0;
 			if (val)
-				fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+				state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
 			else
-				fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+				state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
 		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ready = 0;
+		if (file->f_mode & FMODE_READ) {
+			stop_adc(state);
+			state->dma_adc.ready = 0;
 			if (val)
-				fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+				state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
 			else
-				fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+				state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
 		}
-		set_fmt(s, fmtm, fmtd);
 		return 0;
 
 	case SNDCTL_DSP_GETBLKSIZE:
 		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf(s, 0)))
+			if ((val = prog_dmabuf(state, 0)))
 				return val;
-			return put_user(s->dma_dac.fragsize, (int *)arg);
+			return put_user(state->dma_dac.fragsize, (int *)arg);
+		}
+		if (file->f_mode & FMODE_READ) {
+			if ((val = prog_dmabuf(state, 1)))
+				return val;
+			return put_user(state->dma_adc.fragsize, (int *)arg);
 		}
-		if ((val = prog_dmabuf(s, 1)))
-			return val;
-		return put_user(s->dma_adc.fragsize, (int *)arg);
 
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-		return put_user(AFMT_S8|AFMT_S16_LE, (int *)arg);
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
+		return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT: /* Select sample format */
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val != AFMT_QUERY) {
-			fmtd = 0;
-			fmtm = ~0;
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				/* fixed at 16bit for now */
-				fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
-#if 0
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				state->dma_dac.ready = 0;
 				if (val == AFMT_S16_LE)
-					fmtd |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT;
+					state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
 				else
-					fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT);
-#endif
+					state->dma_dac.fmt &= ~TRIDENT_FMT_16BIT;
 			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				state->dma_adc.ready = 0;
 				if (val == AFMT_S16_LE)
-					fmtd |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
+					state->dma_adc.fmt |= TRIDENT_FMT_16BIT;
 				else
-					fmtm &= ~(TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT);
+					state->dma_adc.fmt &= ~TRIDENT_FMT_16BIT;
 			}
-			set_fmt(s, fmtm, fmtd);
 		}
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-					   (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : 
-					   (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 
-				AFMT_S16_LE : AFMT_S8, (int *)arg);
+		if (file->f_mode & FMODE_WRITE)
+			return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
+					AFMT_S16_LE : AFMT_U8, (int *)arg);
+		else
+			return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
+					AFMT_S16_LE : AFMT_U8, (int *)arg);
 
 	case SNDCTL_DSP_CHANNELS:
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val != 0) {
-			fmtd = 0;
-			fmtm = ~0;
-
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(state);
+				state->dma_dac.ready = 0;
 				if (val >= 2)
-					fmtd |= TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT;
+					state->dma_dac.fmt |= TRIDENT_FMT_STEREO;
 				else
-					fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT);
+					state->dma_dac.fmt &= ~TRIDENT_FMT_STEREO;
 			}
-
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(state);
+				state->dma_adc.ready = 0;
 				if (val >= 2)
-					fmtd |= TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT;
+					state->dma_adc.fmt |= TRIDENT_FMT_STEREO;
 				else
-					fmtm &= ~(TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT);
+					state->dma_adc.fmt &= ~TRIDENT_FMT_STEREO;
 			}
-			set_fmt(s, fmtm, fmtd);
 		}
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-					   (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : 
-					   (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+		if (file->f_mode & FMODE_WRITE)
+			return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+					(int *)arg);
+		else
+			return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+					(int *)arg);
 	case SNDCTL_DSP_POST:
+		/* FIXME: the same as RESET ?? */
 		return 0;
 
 	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || 
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+		if ((file->f_mode & FMODE_READ && state->dma_adc.subdivision) ||
+		    (file->f_mode & FMODE_WRITE && state->dma_dac.subdivision))
 			return -EINVAL;
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
+			state->dma_adc.subdivision = val;
 		if (file->f_mode & FMODE_WRITE)
-			s->dma_dac.subdivision = val;
+			state->dma_dac.subdivision = val;
 		return 0;
 
 	case SNDCTL_DSP_SETFRAGMENT:
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (file->f_mode & FMODE_READ) {
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
+			state->dma_adc.ossfragshift = val & 0xffff;
+			state->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+			if (state->dma_adc.ossfragshift < 4)
+				state->dma_adc.ossfragshift = 4;
+			if (state->dma_adc.ossfragshift > 15)
+				state->dma_adc.ossfragshift = 15;
+			if (state->dma_adc.ossmaxfrags < 4)
+				state->dma_adc.ossmaxfrags = 4;
 		}
 		if (file->f_mode & FMODE_WRITE) {
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
+			state->dma_dac.ossfragshift = val & 0xffff;
+			state->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+			if (state->dma_dac.ossfragshift < 4)
+				state->dma_dac.ossfragshift = 4;
+			if (state->dma_dac.ossfragshift > 15)
+				state->dma_dac.ossfragshift = 15;
+			if (state->dma_dac.ossmaxfrags < 4)
+				state->dma_dac.ossmaxfrags = 4;
 		}
 		return 0;
 
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(0/* DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP */,
-				(int *)arg);
-		
-	case SNDCTL_DSP_SETDUPLEX:
-		/* XXX fix */
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (!state->dma_dac.enable && (val = prog_dmabuf(state, 0)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		abinfo.fragsize = state->dma_dac.fragsize;
+		abinfo.bytes = state->dma_dac.dmasize - state->dma_dac.count;
+		abinfo.fragstotal = state->dma_dac.numfrag;
+		abinfo.fragments = abinfo.bytes >> state->dma_dac.fragshift;      
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!state->dma_adc.enable && (val = prog_dmabuf(state, 1)) != 0)
+			return val;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		abinfo.fragsize = state->dma_adc.fragsize;
+		abinfo.bytes = state->dma_adc.count;
+		abinfo.fragstotal = state->dma_adc.numfrag;
+		abinfo.fragments = abinfo.bytes >> state->dma_adc.fragshift;      
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
 		return 0;
 
+	case SNDCTL_DSP_GETCAPS:
+	    return put_user(/* DSP_CAP_DUPLEX|*/DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
+			    (int *)arg);
+
 	case SNDCTL_DSP_GETTRIGGER:
 		val = 0;
-		if (file->f_mode & FMODE_READ && s->enable & TRIDENT_ENABLE_RE) 
+		if (file->f_mode & FMODE_READ && state->dma_adc.enable) 
 			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && s->enable & TRIDENT_ENABLE_PE) 
+		if (file->f_mode & FMODE_WRITE && state->dma_dac.enable) 
 			val |= PCM_ENABLE_OUTPUT;
 		return put_user(val, (int *)arg);
 
@@ -2568,106 +1627,86 @@
 		get_user_ret(val, (int *)arg, -EFAULT);
 		if (file->f_mode & FMODE_READ) {
 			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready && (ret =	 prog_dmabuf(s, 1)))
+				if (!state->dma_adc.ready && (ret = prog_dmabuf(state, 1)))
 					return ret;
-				start_adc(s);
+				start_adc(state);
 			} 
 			else
-				stop_adc(s);
+				stop_adc(state);
 		}
 		if (file->f_mode & FMODE_WRITE) {
 			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+				if (!state->dma_dac.ready && (ret = prog_dmabuf(state, 0)))
 					return ret;
-				start_dac(s);
+				start_dac(state);
 			} 
 			else
-				stop_dac(s);
+				stop_dac(state);
 		}
 		return 0;
 
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!(s->enable & TRIDENT_ENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
-			return val;
-		spin_lock_irqsave(&s->card->lock, flags);
-		trident_update_ptr(s);
-		abinfo.fragsize = s->dma_dac.fragsize;
-		abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
-		abinfo.fragstotal = s->dma_dac.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
-		spin_unlock_irqrestore(&s->card->lock, flags);
-		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!(s->enable & TRIDENT_ENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
-			return val;
-		spin_lock_irqsave(&s->card->lock, flags);
-		trident_update_ptr(s);
-		abinfo.fragsize = s->dma_adc.fragsize;
-		abinfo.bytes = s->dma_adc.count;
-		abinfo.fragstotal = s->dma_adc.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
-		spin_unlock_irqrestore(&s->card->lock, flags);
-		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_NONBLOCK:
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&s->card->lock, flags);
-		trident_update_ptr(s);
-		val = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->card->lock, flags);
-		return put_user(val, (int *)arg);
-
 	case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		spin_lock_irqsave(&s->card->lock, flags);
-		trident_update_ptr(s);
-		cinfo.bytes = s->dma_adc.total_bytes;
-		cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
-		cinfo.ptr = s->dma_adc.hwptr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= s->dma_adc.fragsize-1;
-		spin_unlock_irqrestore(&s->card->lock, flags);
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		cinfo.bytes = state->dma_adc.total_bytes;
+		cinfo.blocks = state->dma_adc.count >> state->dma_adc.fragshift;
+		cinfo.ptr = state->dma_adc.hwptr;
+		if (state->dma_adc.mapped)
+			state->dma_adc.count &= state->dma_adc.fragsize-1;
+		spin_unlock_irqrestore(&state->card->lock, flags);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 		
 	case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		spin_lock_irqsave(&s->card->lock, flags);
-		trident_update_ptr(s);
-		cinfo.bytes = s->dma_dac.total_bytes;
-		cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
-		cinfo.ptr = s->dma_dac.hwptr;
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= s->dma_dac.fragsize-1;
-		spin_unlock_irqrestore(&s->card->lock, flags);
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		cinfo.bytes = state->dma_dac.total_bytes;
+		cinfo.blocks = state->dma_dac.count >> state->dma_dac.fragshift;
+		cinfo.ptr = state->dma_dac.hwptr;
+		if (state->dma_dac.mapped)
+			state->dma_dac.count &= state->dma_dac.fragsize-1;
+		spin_unlock_irqrestore(&state->card->lock, flags);
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
+	case SNDCTL_DSP_SETDUPLEX:
+		/* XXX fix */
+		return 0;
+
+	case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&state->card->lock, flags);
+		trident_update_ptr(state);
+		val = state->dma_dac.count;
+		spin_unlock_irqrestore(&state->card->lock, flags);
+		return put_user(val, (int *)arg);
+
 	case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+		return put_user((file->f_mode & FMODE_READ) ? state->dma_adc.rate :
+				state->dma_dac.rate, (int *)arg);
 
 	case SOUND_PCM_READ_CHANNELS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-					   (TRIDENT_FMT_STEREO << TRIDENT_ADC_SHIFT) : 
-					   (TRIDENT_FMT_STEREO << TRIDENT_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+		if (file->f_mode & FMODE_WRITE)
+			return put_user((state->dma_dac.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+					(int *)arg);
+		else
+			return put_user((state->dma_adc.fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+					(int *)arg);
 		
 	case SOUND_PCM_READ_BITS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-					   (TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT) : 
-					   (TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT))) ? 16 : 8, (int *)arg);
-		
-	case SOUND_PCM_WRITE_FILTER:
+		if (file->f_mode & FMODE_WRITE)
+			return put_user((state->dma_dac.fmt & TRIDENT_FMT_16BIT) ?
+					AFMT_S16_LE : AFMT_U8, (int *)arg);
+		else
+			return put_user((state->dma_adc.fmt & TRIDENT_FMT_16BIT) ?
+					AFMT_S16_LE : AFMT_U8, (int *)arg);
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
 	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_WRITE_FILTER:
 	case SOUND_PCM_READ_FILTER:
 		return -EINVAL;
 		
@@ -2681,13 +1720,12 @@
 	int minor = MINOR(inode->i_rdev);
 	struct trident_card *card = devs;
 	struct trident_state *state = NULL;
-	unsigned char fmtm = ~0, fmts = 0;
 
 	/* find an avaiable virtual channel (instance of /dev/dsp) */
 	while (card != NULL) {
-		for (i = 0; i < NR_DSPS; i++) {
-			if (card->channels[i] == NULL) {
-				state = card->channels[i] = (struct trident_state *)
+		for (i = 0; i < NR_HW_CH; i++) {
+			if (card->states[i] == NULL) {
+				state = card->states[i] = (struct trident_state *)
 					kmalloc(sizeof(struct trident_state), GFP_KERNEL);
 				if (state == NULL)
 					return -ENOMEM;
@@ -2704,18 +1742,18 @@
  found_virt:
 	/* found a free virtual channel, allocate hardware channels */
 	if (file->f_mode & FMODE_READ)
-		if ((state->dma_adc.chan = trident_alloc_pcm_channel(card)) == -1) {
-			kfree (card->channels[i]);
-			card->channels[i] = NULL;;
+		if ((state->dma_adc.channel = trident_alloc_pcm_channel(card)) == NULL) {
+			kfree (card->states[i]);
+			card->states[i] = NULL;;
 			return -ENODEV;
 		}
 	if (file->f_mode & FMODE_WRITE)
-		if ((state->dma_dac.chan = trident_alloc_pcm_channel(card)) == -1) {
-			kfree (card->channels[i]);
-			card->channels[i] = NULL;
+		if ((state->dma_dac.channel = trident_alloc_pcm_channel(card)) == NULL) {
+			kfree (card->states[i]);
+			card->states[i] = NULL;
 			if (file->f_mode & FMODE_READ)
 				/* free previously allocated hardware channel */
-				trident_free_pcm_channel(card, state->dma_adc.chan);
+				trident_free_pcm_channel(card, state->dma_adc.channel->num);
 			return -ENODEV;
 		}
 
@@ -2732,30 +1770,27 @@
 
 	/* set default sample format, Refer to  OSS Programmer's Guide */
 	if (file->f_mode & FMODE_READ) {
-		/* fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= TRIDENT_FMT_16BIT << TRIDENT_ADC_SHIFT; */
-		fmtm = (TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT) << TRIDENT_ADC_SHIFT;
+		/* FIXME: Trident 4d can only record in singed 16-bits stereo, 48kHz sample */
+		state->dma_adc.fmt = TRIDENT_FMT_STEREO|TRIDENT_FMT_16BIT;
 		state->dma_adc.ossfragshift = 0;
 		state->dma_adc.ossmaxfrags  = 0;
 		state->dma_adc.subdivision  = 0;
-		trident_set_adc_rate(state, 8000, 0);
+		trident_set_adc_rate(state, 48000);
 	}
 
 	/* according to OSS document, /dev/dsp should be default to unsigned 8-bits, 
 	   mono, with sample rate 8kHz and /dev/dspW will accept 16-bits sample */
 	if (file->f_mode & FMODE_WRITE) {
-		fmtm &= ~((TRIDENT_FMT_STEREO | TRIDENT_FMT_16BIT) << TRIDENT_DAC_SHIFT);
+		state->dma_dac.fmt &= ~TRIDENT_FMT_MASK;
 		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= TRIDENT_FMT_16BIT << TRIDENT_DAC_SHIFT;
+			 state->dma_dac.fmt |= TRIDENT_FMT_16BIT;
 		state->dma_dac.ossfragshift = 0;
 		state->dma_dac.ossmaxfrags  = 0;
 		state->dma_dac.subdivision  = 0;
-		trident_set_dac_rate(state, 8000, 1);
+		trident_set_dac_rate(state, 8000);
 	}
-	set_fmt(state, fmtm, fmts);
-	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 
+	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 	up(&state->open_sem);
 
 	//FIXME put back in
@@ -2768,8 +1803,12 @@
 	struct trident_state *state = (struct trident_state *)file->private_data;
 
 	VALIDATE_STATE(state);
-	if (file->f_mode & FMODE_WRITE)
+
+
+	if (file->f_mode & FMODE_WRITE) {
+		trident_clear_tail(state);
 		drain_dac(state, file->f_flags & O_NONBLOCK);
+	}
 
 	/* stop DMA state machine and free DMA buffers/channels */
 	down(&state->open_sem);
@@ -2777,16 +1816,16 @@
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(state);
 		dealloc_dmabuf(&state->dma_dac);
-		trident_free_pcm_channel(state->card, state->dma_dac.chan);
+		trident_free_pcm_channel(state->card, state->dma_dac.channel->num);
 	}
 	if (file->f_mode & FMODE_READ) {
 		stop_adc(state);
 		dealloc_dmabuf(&state->dma_adc);
-		trident_free_pcm_channel(state->card, state->dma_adc.chan);
+		trident_free_pcm_channel(state->card, state->dma_adc.channel->num);
 	}
 
-	kfree(state->card->channels[state->virt]);
-	state->card->channels[state->virt] = NULL;
+	kfree(state->card->states[state->virt]);
+	state->card->states[state->virt] = NULL;
 	state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
 	/* we're covered by the open_sem */
@@ -2796,6 +1835,7 @@
 	//MOD_DEC_USE_COUNT;
 	return 0;
 }
+
 static /*const*/ struct file_operations trident_audio_fops = {
 	&trident_llseek,
 	&trident_read,
@@ -2803,7 +1843,7 @@
 	NULL,	/* readdir */
 	&trident_poll,
 	&trident_ioctl,
-	NULL,	/* XXX &trident_mmap, */
+	&trident_mmap,
 	&trident_open,
 	NULL,	/* flush */
 	&trident_release,
@@ -2812,15 +1852,238 @@
 	NULL,	/* lock */
 };
 
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   untill open time */
-static int trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
+/* trident specific AC97 functions */
+/* Write AC97 mixer registers */
+static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask, busy;
+	unsigned short count  = 0xffff;
+	unsigned long flags;
+	u32 data;
+
+	data = ((u32) val) << 16;
+
+	switch (card->pci_id)
+	{
+	default:
+	case PCI_DEVICE_ID_SI_7018:
+		address = SI_AC97_WRITE;
+		mask = SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY;
+		if (codec->id)
+		    mask |= SI_AC97_SECONDARY;
+		busy = SI_AC97_BUSY_WRITE;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		address = DX_ACR0_AC97_W;
+		mask = busy = DX_AC97_BUSY_WRITE;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		address = NX_ACR1_AC97_W;
+		mask = NX_AC97_BUSY_WRITE;
+		if (codec->id)
+		    mask |= NX_AC97_WRITE_SECONDARY;
+		busy = NX_AC97_BUSY_WRITE;
+		break;
+	}
+
+	spin_lock_irqsave(&card->lock, flags);
+	do {
+		if ((inw(TRID_REG(card, address)) & busy) == 0)
+			break;
+	} while (count--);
+
+
+	data |= (mask | (reg & AC97_REG_ADDR));
+
+	if (count == 0) {
+		printk(KERN_ERR "trident: AC97 CODEC write timed out.\n");
+		spin_unlock_irqrestore(&card->lock, flags);
+		return;
+	}
+
+	outl(data, TRID_REG(card, address));
+	spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/* Read AC97 codec registers */
+static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg)
+{
+	struct trident_card *card = (struct trident_card *)codec->private_data;
+	unsigned int address, mask, busy;
+	unsigned short count = 0xffff;
+	unsigned long flags;
+	u32 data;
+
+	switch (card->pci_id)
+	{
+	default:
+	case PCI_DEVICE_ID_SI_7018:
+		address = SI_AC97_READ;
+		mask = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY;
+		if (codec->id)
+		    mask |= SI_AC97_SECONDARY;
+		busy = SI_AC97_BUSY_READ;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		address = DX_ACR1_AC97_R;
+		mask = busy = DX_AC97_BUSY_READ;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		if (codec->id)
+			address = NX_ACR3_AC97_R_SECONDARY;
+		else
+			address = NX_ACR2_AC97_R_PRIMARY;
+		mask = NX_AC97_BUSY_READ;
+		busy = 0x0c00;
+		break;
+	}
+
+	data = (mask | (reg & AC97_REG_ADDR));
+
+	spin_lock_irqsave(&card->lock, flags);
+	outl(data, TRID_REG(card, address));
+	do {
+		data = inl(TRID_REG(card, address));
+		if ((data & busy) == 0)
+			break;
+	} while (count--);
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	if (count == 0) {
+		printk(KERN_ERR "trident: AC97 CODEC read timed out.\n");
+		data = 0;
+	}
+	return ((u16) (data >> 16));
+}
+
+/* OSS /dev/mixer file operation methods */
+static int trident_open_mixdev(struct inode *inode, struct file *file)
 {
 	int i;
+	int minor = MINOR(inode->i_rdev);
+	struct trident_card *card = devs;
+
+	for (card = devs; card != NULL; card = card->next)
+		for (i = 0; i < NR_AC97; i++)
+			if (card->ac97_codec[i] != NULL &&
+			    card->ac97_codec[i]->dev_mixer == minor)
+				goto match;
+
+	if (!card)
+		return -ENODEV;
+
+ match:
+	file->private_data = card->ac97_codec[i];
+
+	//FIXME put back in
+	//MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int trident_release_mixdev(struct inode *inode, struct file *file)
+{
+	//struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+	//FIXME put back in
+	//MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+	return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const*/ struct file_operations trident_mixer_fops = {
+	&trident_llseek,
+	NULL,  /* read */
+	NULL,  /* write */
+	NULL,  /* readdir */
+	NULL,  /* poll */
+	&trident_ioctl_mixdev,
+	NULL,  /* mmap */
+	&trident_open_mixdev,
+	NULL,	/* flush */
+	&trident_release_mixdev,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* lock */
+};
+
+/* AC97 codec initialisation. */
+static int __init trident_ac97_init(struct trident_card *card)
+{
+	int num_ac97 = 0;
+	int ready_2nd = 0;
+	struct ac97_codec *codec;
+
+	/* initialize controller side of AC link, and find out if secondary codes
+	   really exist */
+	switch (card->pci_id)
+	{
+	case PCI_DEVICE_ID_SI_7018:
+		/* disable AC97 GPIO interrupt */
+		outl(0x00, TRID_REG(card, SI_AC97_GPIO));
+		/* stop AC97 cold reset process */
+		outl(PCMOUT|SECONDARY_ID, TRID_REG(card, SI_SERIAL_INTF_CTRL));
+		ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL)); 
+		ready_2nd &= SI_AC97_SECONDARY_READY;
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_DX:
+		/* playback on */
+		outl(DX_AC97_PLAYBACK, TRID_REG(card, DX_ACR2_AC97_COM_STAT));
+		break;
+	case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
+		/* enable AC97 Output Slot 3,4 (PCM Left/Right Playback) */
+		outl(NX_AC97_PCM_OUTPUT, TRID_REG(card, NX_ACR0_AC97_COM_STAT));
+		ready_2nd = inl(TRID_REG(card, NX_ACR0_AC97_COM_STAT));
+		ready_2nd &= NX_AC97_SECONDARY_READY;
+		break;
+	}
+
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+			return -1;
+		memset(codec, 0, sizeof(struct ac97_codec));
+
+		/* initialize some basic codec information, other fields will be filled
+		   in ac97_probe_codec */
+		codec->private_data = card;
+		codec->id = num_ac97;
+		/* controller specific low level AC97 access function */
+		codec->codec_read = trident_ac97_get;
+		codec->codec_write = trident_ac97_set;
+
+		if (ac97_probe_codec(codec) == 0)
+			break;
+
+		if ((codec->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
+			printk(KERN_ERR "trident: couldn't register mixer!\n");
+			kfree(codec);
+			break;
+		}
+
+		card->ac97_codec[num_ac97] = codec;
+
+		/* if there is no secondary codec at all, don't probe any more */
+		if (!ready_2nd)
+			return num_ac97+1;
+	}
+
+	return num_ac97;
+}
+
+/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
+   untill "ACCESS" time (in prog_dmabuf calles by open/read/write/ioctl/mmap) */
+static int __init trident_install(struct pci_dev *pcidev, struct pci_audio_info *pci_info)
+{
 	u16 w;
 	unsigned long iobase;
 	struct trident_card *card;
-    	u32 ChanDwordCount;
 
 	iobase = pcidev->resource[0].start;
 	if (check_region(iobase, 256)) {
@@ -2847,30 +2110,12 @@
 	card->irq = pcidev->irq;
 	card->next = devs;
 	card->magic = TRIDENT_CARD_MAGIC;
+	card->banks[BANK_A].addresses = &bank_a_addrs;
+	card->banks[BANK_A].bitmap = 0UL;
+	card->banks[BANK_B].addresses = &bank_b_addrs;
+	card->banks[BANK_B].bitmap = 0UL;
 	spin_lock_init(&card->lock);
-	devs = card;
-
-	/* ungly stupid thing, remove ASAP */
-	ChanDwordCount = card->ChanDwordCount = 2;
-	card->ChRegs.lpChStart = card->ChRegs.data;
-	card->ChRegs.lpChStop = card->ChRegs.lpChStart + ChanDwordCount;
-	card->ChRegs.lpChAint = card->ChRegs.lpChStop + ChanDwordCount;
-	card->ChRegs.lpChAinten = card->ChRegs.lpChAint + ChanDwordCount;
-	card->ChRegs.lpAChStart = card->ChRegs.lpChAinten + ChanDwordCount;
-	card->ChRegs.lpAChStop = card->ChRegs.lpAChStart + ChanDwordCount;
-	card->ChRegs.lpAChAint = card->ChRegs.lpAChStop + ChanDwordCount;
-	card->ChRegs.lpAChAinten = card->ChRegs.lpAChAint + ChanDwordCount;
-	// Assign Bank A addresses.
-	card->ChRegs.lpAChStart[0] = T4D_START_A;
-	card->ChRegs.lpAChStop[0] = T4D_STOP_A;
-	card->ChRegs.lpAChAint[0] = T4D_AINT_A;
-	card->ChRegs.lpAChAinten[0] = T4D_AINTEN_A;
-	/* Assign Bank B addresses */
-	card->ChRegs.lpAChStart[1] = T4D_START_B;
-	card->ChRegs.lpAChStop[1] = T4D_STOP_B;
-	card->ChRegs.lpAChAint[1] = T4D_AINT_B;
-	card->ChRegs.lpAChAinten[1] = T4D_AINTEN_B;
-
+	devs = card;	
 
 	printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
 	       card->pci_info->name, card->iobase, card->irq);
@@ -2883,11 +2128,6 @@
 		kfree(card);
 		return 0;
 	}
-
-	/* initilize AC97 codec */
-	trident_ac97_init(card);
-	outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
-
 	/* register /dev/dsp */
 	if ((card->dev_audio = register_sound_dsp(&trident_audio_fops, -1)) < 0) {
 		printk(KERN_ERR "trident: coundn't register DSP device!\n");
@@ -2896,29 +2136,18 @@
 		kfree(card);
 		return 0;
 	}
-	/* register /dev/mixer */
-	if ((card->dev_mixer = register_sound_mixer(&trident_mixer_fops, -1)) < 0) {
-		printk(KERN_ERR "trident: couldn't register mixer!\n");
+	/* initilize AC97 codec and register /dev/mixer */
+	if (trident_ac97_init(card) <= 0) {
 		unregister_sound_dsp(card->dev_audio);
 		release_region(iobase, 256);
 		free_irq(card->irq, card);
 		kfree(card);
 		return 0;
-	} else {
-		/* initilize mixer channels */
-		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			struct mixer_defaults *md = &mixer_defaults[i];
-			if (md->mixer == -1) 
-				break;
-			if (!supported_mixer(card, md->mixer)) 
-				continue;
-			set_mixer(card, md->mixer, md->value);
-		}
 	}
+	outl(0x00, TRID_REG(card, T4D_MUSICVOL_WAVEVOL));
 
 	/* Enable Address Engine Interrupts */
-	trident_enable_end_interrupts(card);
-	trident_enable_middle_interrupts(card);
+	trident_enable_loop_interrupts(card);
 
 	return 1; 
 }
@@ -2952,23 +2181,23 @@
 MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho");
 MODULE_DESCRIPTION("Trident 4DWave/SiS 7018 PCI Audio Driver");
 
-#ifdef DEBUG
-MODULE_PARM(debug,"i");
-#endif
-
 static void __exit cleanup_trident(void)
 {
 	while (devs != NULL) {
+		int i;
 		/* Kill interrupts, and SP/DIF */
-		trident_disable_end_interrupts(devs);
-		trident_enable_middle_interrupts(devs);
+		trident_disable_loop_interrupts(devs);
 
 		/* free hardware resources */
 		free_irq(devs->irq, devs);
 		release_region(devs->iobase, 256);
 
 		/* unregister audio devices */
-		unregister_sound_mixer(devs->dev_mixer);
+		for (i = 0; i < NR_AC97; i++)
+			if (devs->ac97_codec[i] != NULL) {
+				unregister_sound_mixer(devs->ac97_codec[i]->dev_mixer);
+				kfree (devs->ac97_codec[i]);
+			}
 		unregister_sound_dsp(devs->dev_audio);
 
 		kfree(devs);
@@ -2978,5 +2207,3 @@
 
 module_init(init_trident);
 module_exit(cleanup_trident);
-
-
diff -u --recursive --new-file v2.3.41/linux/drivers/sound/trident.h linux/drivers/sound/trident.h
--- v2.3.41/linux/drivers/sound/trident.h	Fri Jan  7 19:13:22 2000
+++ linux/drivers/sound/trident.h	Fri Jan 28 19:36:23 2000
@@ -23,6 +23,7 @@
  *
  */
 
+/* PCI vendor and device ID */ 
 #ifndef PCI_VENDOR_ID_TRIDENT
 #define PCI_VENDOR_ID_TRIDENT		0x1023
 #endif
@@ -43,118 +44,101 @@
 #define PCI_DEVICE_ID_SI_7018		0x7018
 #endif
 
-/*
- * Direct registers
- */
-
 #ifndef FALSE
-#define FALSE 0
-#define TRUE  1
+#define FALSE 		0
+#define TRUE  		1
 #endif
 
-#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
-
 #define CHANNEL_REGS	5
 #define CHANNEL_START	0xe0   // The first bytes of the contiguous register space.
 
-#define BANK_A 0
-#define BANK_B 1
-#define NUM_BANKS 2
-
-#define ID_4DWAVE_DX	0x2000
-#define ID_4DWAVE_NX	0x2001
-#define ID_SI_7018	0x7018
-
-// Register definitions
-
-// Global registers
-
-// T2 legacy dma control registers.
-#define LEGACY_DMAR0		0x00  // ADR0
-#define LEGACY_DMAR4		0x04  // CNT0
-#define LEGACY_DMAR11		0x0b  // MOD 
-#define LEGACY_DMAR15		0x0f  // MMR 
-
-#define T4D_START_A		0x80
-#define T4D_STOP_A		0x84
-#define T4D_DLY_A			0x88
-#define T4D_SIGN_CSO_A		0x8c
-#define T4D_CSPF_A		0x90
-#define T4D_CEBC_A		0x94
-#define T4D_AINT_A		0x98
-#define T4D_EINT_A		0x9c
-#define T4D_LFO_GC_CIR		0xa0
-#define T4D_AINTEN_A		0xa4
-#define T4D_MUSICVOL_WAVEVOL	0xa8
-#define T4D_SBDELTA_DELTA_R	0xac
-#define T4D_MISCINT		0xb0
-#define T4D_START_B		0xb4
-#define T4D_STOP_B		0xb8
-#define T4D_CSPF_B		0xbc
-#define T4D_SBBL_SBCL		0xc0
-#define T4D_SBCTRL_SBE2R_SBDD	0xc4
-#define T4D_STIMER		0xc8
-#define T4D_LFO_B_I2S_DELTA	0xcc
-#define T4D_AINT_B		0xd8
-#define T4D_AINTEN_B		0xdc
-
-// MPU-401 UART
-#define T4D_MPU401_BASE		0x20
-#define T4D_MPUR0			0x20
-#define T4D_MPUR1			0x21
-#define T4D_MPUR2			0x22
-#define T4D_MPUR3			0x23
-
-// S/PDIF Registers
-#define NX_SPCTRL_SPCSO		0x24
-#define NX_SPLBA			0x28
-#define NX_SPESO			0x2c
-#define NX_SPCSTATUS		0x64
-
-// Channel Registers
-
-#define CH_DX_CSO_ALPHA_FMS	0xe0
-#define CH_DX_ESO_DELTA		0xe8
-#define CH_DX_FMC_RVOL_CVOL	0xec
-
-#define CH_NX_DELTA_CSO		0xe0
-#define CH_NX_DELTA_ESO		0xe8
-#define CH_NX_ALPHA_FMS_FMC_RVOL_CVOL 0xec
-
-#define CH_LBA			0xe4
-#define CH_GVSEL_PAN_VOL_CTRL_EC	0xf0
-
-// AC-97 Registers
-
-#define DX_ACR0_AC97_W		0x40
-#define DX_ACR1_AC97_R		0x44
-#define DX_ACR2_AC97_COM_STAT	0x48
-
-#define NX_ACR0_AC97_COM_STAT	0x40
-#define NX_ACR1_AC97_W		0x44
-#define NX_ACR2_AC97_R_PRIMARY	0x48
-#define NX_ACR3_AC97_R_SECONDARY	0x4c
-
-#define SI_AC97_WRITE		0x40
-#define SI_AC97_READ		0x44
-#define SI_SERIAL_INTF_CTRL	0x48
-#define SI_AC97_GPIO		0x4c
+#define BANK_A 		0
+#define BANK_B 		1
+#define NR_BANKS		2
+
+#define TRIDENT_FMT_STEREO     0x01
+#define TRIDENT_FMT_16BIT      0x02
+#define TRIDENT_FMT_MASK       0x03
+
+#define DMA_ENABLE	0x01
+#define DMA_RUNNING	0x02
+
+/* Register Addresses */
+
+/* operational registers common to DX, NX, 7018 */
+enum trident_op_registers {
+	T4D_START_A     = 0x80, T4D_STOP_A      = 0x84,
+	T4D_DLY_A       = 0x88, T4D_SIGN_CSO_A  = 0x8c,
+	T4D_CSPF_A      = 0x90, T4D_CEBC_A      = 0x94,
+	T4D_AINT_A      = 0x98, T4D_EINT_A	= 0x9c,
+	T4D_LFO_GC_CIR	= 0xa0, T4D_AINTEN_A    = 0xa4,
+	T4D_MUSICVOL_WAVEVOL = 0xa8, T4D_SBDELTA_DELTA_R = 0xac,
+	T4D_MISCINT	= 0xb0, T4D_START_B     = 0xb4,
+	T4D_STOP_B      = 0xb8, T4D_CSPF_B	= 0xbc,
+	T4D_SBBL_SBCL	= 0xc0, T4D_SBCTRL_SBE2R_SBDD    = 0xc4,
+	T4D_STIMER	= 0xc8, T4D_LFO_B_I2S_DELTA      = 0xcc,
+	T4D_AINT_B	= 0xd8, T4D_AINTEN_B    = 0xdc
+};
 
-#define AC97_SIGMATEL_DAC2INVERT	0x6E
-#define AC97_SIGMATEL_BIAS1	0x70
-#define AC97_SIGMATEL_BIAS2	0x72
-#define AC97_SIGMATEL_CIC1	0x76
-#define AC97_SIGMATEL_CIC2	0x78
+/* S/PDIF Operational Registers for 4D-NX */
+enum nx_spdif_registers {
+	NX_SPCTRL_SPCSO	= 0x24, NX_SPLBA = 0x28,
+	NX_SPESO	= 0x2c, NX_SPCSTATUS = 0x64
+};
+
+/* OP registers to access each hardware channel */
+enum channel_registers {
+	CH_DX_CSO_ALPHA_FMS = 0xe0, CH_DX_ESO_DELTA = 0xe8,
+	CH_DX_FMC_RVOL_CVOL = 0xec,
+	CH_NX_DELTA_CSO     = 0xe0, CH_NX_DELTA_ESO = 0xe8,
+	CH_NX_ALPHA_FMS_FMC_RVOL_CVOL = 0xec,
+	CH_LBA              = 0xe4,
+	CH_GVSEL_PAN_VOL_CTRL_EC      = 0xf0
+};
+
+/* registers to read/write/control AC97 codec */
+enum dx_ac97_registers {
+	DX_ACR0_AC97_W        = 0x40, DX_ACR1_AC97_R = 0x44,
+	DX_ACR2_AC97_COM_STAT = 0x48
+};
+
+enum nx_ac97_registers {
+	NX_ACR0_AC97_COM_STAT  = 0x40, NX_ACR1_AC97_W           = 0x44,
+	NX_ACR2_AC97_R_PRIMARY = 0x48, NX_ACR3_AC97_R_SECONDARY	= 0x4c
+};
+
+enum si_ac97_registers {
+	SI_AC97_WRITE       = 0x40, SI_AC97_READ = 0x44,
+	SI_SERIAL_INTF_CTRL = 0x48, SI_AC97_GPIO = 0x4c
+};
 
-#define SI_AC97_BUSY_WRITE 0x8000
-#define SI_AC97_AUDIO_BUSY 0x4000
-#define DX_AC97_BUSY_WRITE 0x8000
-#define NX_AC97_BUSY_WRITE 0x0800
-#define SI_AC97_BUSY_READ  0x8000
-#define DX_AC97_BUSY_READ  0x8000
-#define NX_AC97_BUSY_READ  0x0800
+/* Bit mask for operational registers */
 #define AC97_REG_ADDR      0x000000ff
 
+enum sis7018_ac97_bits {
+	SI_AC97_BUSY_WRITE = 0x8000, SI_AC97_BUSY_READ = 0x8000,
+	SI_AC97_AUDIO_BUSY = 0x4000, SI_AC97_MODEM_BUSY = 0x2000,
+	SI_AC97_SECONDARY  = 0x0080
+};
+
+enum trident_dx_ac97_bits {
+	DX_AC97_BUSY_WRITE = 0x8000, DX_AC97_BUSY_READ = 0x8000,
+	DX_AC97_READY      = 0x0010, DX_AC97_RECORD    = 0x0008,
+	DX_AC97_PLAYBACK   = 0x0002
+};
+
+enum trident_nx_ac97_bits {
+	/* ACR1-3 */
+	NX_AC97_BUSY_WRITE = 0x0800, NX_AC97_BUSY_READ = 0x0800,
+	NX_AC97_WRITE_SECONDARY = 0x0100,
+	/* ACR0 */
+	NX_AC97_SECONDARY_READY = 0x0040, NX_AC97_SECONDARY_RECORD = 0x0020,
+	NX_AC97_SURROUND_OUTPUT = 0x0010,
+	NX_AC97_PRIMARY_READY   = 0x0008, NX_AC97_PRIMARY_RECORD   = 0x0004,
+	NX_AC97_PCM_OUTPUT      = 0x0002,
+	NX_AC97_WARM_RESET      = 0x0001
+};
+
 enum serial_intf_ctrl_bits {
 	WARM_REST   = 0x00000001, COLD_RESET  = 0x00000002,
 	I2S_CLOCK   = 0x00000004, PCM_SEC_AC97= 0x00000008,
@@ -162,6 +146,16 @@
 	I2S_OUTPUT_EN = 0x00000040, I2S_INPUT_EN = 0x00000080,
 	PCMIN       = 0x00000100, LINE1IN     = 0x00000200,
 	MICIN       = 0x00000400, LINE2IN     = 0x00000800,
+	HEAD_SET_IN = 0x00001000, GPIOIN      = 0x00002000,
+	/* 7018 spec says id = 01 but the demo board routed to 10 
+	   SECONDARY_ID= 0x00008000, */
+	SECONDARY_ID= 0x00004000,
+	PCMOUT      = 0x00010000, SURROUT     = 0x00020000,
+	CENTEROUT   = 0x00040000, LFEOUT      = 0x00080000,
+	LINE1OUT    = 0x00100000, LINE2OUT    = 0x00200000,
+	GPIOOUT     = 0x00400000,
+	SI_AC97_PRIMARY_READY   = 0x01000000,
+	SI_AC97_SECONDARY_READY = 0x02000000,
 };
 
 enum global_control_bits {
@@ -173,6 +167,18 @@
 	EDROP_IE    = 0x00008000, BANK_B_EN   = 0x00010000
 };
 
+enum channel_control_bits {
+	CHANNEL_LOOP   = 0x00001000, CHANNEL_SIGNED = 0x00002000,
+	CHANNEL_STEREO = 0x00004000, CHANNEL_16BITS = 0x00008000,
+};
+
+enum channel_attribute {
+	MODEM_LINE1, MODEM_LINE2, PCM_LR, HSET,
+	I2SLR, CENTER_LFE, SURR_LR, SPDIF_LR,
+	CHANNEL_PB     = 0x00000000, CHANNEL_SPC_PB = 0x40000000,
+	CHANNEL_REC    = 0x80000000, CHANNEL_REC_PB = 0xc0000000
+};
+
 enum miscint_bits {
 	PB_UNDERRUN_IRO = 0x00000001, REC_OVERRUN_IRQ = 0x00000002,
 	SB_IRQ          = 0x00000004, MPU401_IRQ      = 0x00000008,
@@ -184,31 +190,13 @@
 	ST_IRQ_EN       = 0x00800000, ACGPIO_IRQ      = 0x01000000
 };
 
-#define IWriteAinten( x ) \
-	{int i; \
-	 for( i= 0; i < ChanDwordCount; i++) \
-		outl((x)->lpChAinten[i], TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define IReadAinten( x ) \
-	{int i; \
-	 for( i= 0; i < ChanDwordCount; i++) \
-	 (x)->lpChAinten[i] = inl(TRID_REG(trident, (x)->lpAChAinten[i]));}
-
-#define ReadAint( x ) \
-	IReadAint( x ) 
-
-#define WriteAint( x ) \
-	IWriteAint( x ) 
-
-#define IWriteAint( x ) \
-	{int i; \
-	 for( i= 0; i < ChanDwordCount; i++) \
-	 outl((x)->lpChAint[i], TRID_REG(trident, (x)->lpAChAint[i]));}
-
-#define IReadAint( x ) \
-	{int i; \
-	 for( i= 0; i < ChanDwordCount; i++) \
-	 (x)->lpChAint[i] = inl(TRID_REG(trident, (x)->lpAChAint[i]));}
+#define AC97_SIGMATEL_DAC2INVERT	0x6E
+#define AC97_SIGMATEL_BIAS1	0x70
+#define AC97_SIGMATEL_BIAS2	0x72
+#define AC97_SIGMATEL_CIC1	0x76
+#define AC97_SIGMATEL_CIC2	0x78
+
+#define TRID_REG( trident, x ) ( (trident) -> iobase + (x) )
 
 #define VALIDATE_MAGIC(FOO,MAG)				\
 ({						  \
@@ -220,6 +208,32 @@
 
 #define VALIDATE_STATE(a) VALIDATE_MAGIC(a,TRIDENT_STATE_MAGIC)
 #define VALIDATE_CARD(a) VALIDATE_MAGIC(a,TRIDENT_CARD_MAGIC)
+
+ 
+extern __inline__ unsigned ld2(unsigned int x)
+{
+	unsigned r = 0;
+	
+	if (x >= 0x10000) {
+		x >>= 16;
+		r += 16;
+	}
+	if (x >= 0x100) {
+		x >>= 8;
+		r += 8;
+	}
+	if (x >= 0x10) {
+		x >>= 4;
+		r += 4;
+	}
+	if (x >= 4) {
+		x >>= 2;
+		r += 2;
+	}
+	if (x >= 2)
+		r++;
+	return r;
+}
 
 #endif /* __TRID4DWAVE_H */
 
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.41/linux/drivers/usb/Config.in	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/Config.in	Mon Jan 31 10:10:07 2000
@@ -9,6 +9,7 @@
 
 comment 'USB Controllers'
    dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+   dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
    dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
 
 comment 'Miscellaneous USB options'
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.41/linux/drivers/usb/Makefile	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/Makefile	Mon Jan 31 10:10:07 2000
@@ -45,6 +45,7 @@
 
 obj-$(CONFIG_USB)		+= usbcore.o
 obj-$(CONFIG_USB_UHCI)		+= usb-uhci.o
+obj-$(CONFIG_USB_UHCI_ALT)	+= uhci.o
 obj-$(CONFIG_USB_OHCI)		+= usb-ohci.o
 
 obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o input.o
@@ -107,3 +108,4 @@
 
 usb-storage.o: $(usb-storage-objs)
 	$(LD) -r -o $@ $(usb-storage-objs)
+
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.41/linux/drivers/usb/acm.c	Fri Jan 21 18:19:17 2000
+++ linux/drivers/usb/acm.c	Mon Jan 31 10:09:22 2000
@@ -1,5 +1,5 @@
 /*
- * acm.c  Version 0.14
+ * acm.c  Version 0.15
  *
  * Copyright (c) 1999 Armin Fuerst	<fuerst@in.tum.de>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
@@ -17,6 +17,7 @@
  *	v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
  *	v0.13 - added termios, added hangup
  *	v0.14 - sized down struct acm
+ *	v0.15 - fixed flow control again - characters could be lost
  */
 
 /*
@@ -137,6 +138,7 @@
 	unsigned int writesize;				/* max packet size for the output bulk endpoint */
 	unsigned int used;				/* someone has this acm's device open */
 	unsigned int minor;				/* acm minor number */
+	unsigned char throttle;				/* throttled by tty layer */
 	unsigned char clocal;				/* termios CLOCAL */
 };
 
@@ -210,8 +212,6 @@
 				dr->request, dr->index, dr->length, data[0], data[1]);
 			return;
 	}
-
-	return;
 }
 
 static void acm_read_bulk(struct urb *urb)
@@ -219,24 +219,25 @@
 	struct acm *acm = urb->context;
 	struct tty_struct *tty = acm->tty;
 	unsigned char *data = urb->transfer_buffer;
-	int i;
+	int i = 0;
 
 	if (!ACM_READY(acm)) return;
 
-	if (!urb->status)  {
-
-		for (i = 0; i < urb->actual_length; i++)
+	if (!urb->status & !acm->throttle)  {
+		for (i = 0; i < urb->actual_length && !acm->throttle; i++)
 			tty_insert_flip_char(tty, data[i], 0);
-
 		tty_flip_buffer_push(tty);
-
 	} else
 		dbg("nonzero read bulk status received: %d", urb->status);
 
-	if (usb_submit_urb(urb))
-		dbg("failed resubmitting read urb");
-
-	return;
+	if (!acm->throttle) {
+		urb->actual_length = 0;
+		if (usb_submit_urb(urb))
+			dbg("failed resubmitting read urb");
+	} else {
+		memmove(data, data + i, urb->actual_length - i);
+		urb->actual_length -= i;
+	}
 }
 
 static void acm_write_bulk(struct urb *urb)
@@ -253,8 +254,6 @@
 		(tty->ldisc.write_wakeup)(tty);
 
 	wake_up_interruptible(&tty->write_wait);
-
-	return;
 }
 
 /*
@@ -347,15 +346,16 @@
 {
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm)) return;
-	usb_unlink_urb(&acm->readurb);	
+	acm->throttle = 1;
 }
 
 static void acm_tty_unthrottle(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm)) return;
-	if (usb_submit_urb(&acm->readurb))
-		dbg("usb_submit_urb(read bulk) in unthrottle() failed");
+	acm->throttle = 0;
+	if (acm->readurb.status != -EINPROGRESS)
+		acm_read_bulk(&acm->readurb);
 }
 
 static void acm_tty_break_ctl(struct tty_struct *tty, int state)
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.3.41/linux/drivers/usb/ov511.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/ov511.c	Mon Jan 31 10:09:30 2000
@@ -931,7 +931,7 @@
 		err("ov511_init_isoc: usb_run_isoc(0) ret %d", err);
 	err = usb_submit_urb(ov511->sbuf[1].urb);
 	if (err)
-		err("ov511_init_isoc: usb_run_isoc(1) ret %d\n", err);
+		err("ov511_init_isoc: usb_run_isoc(1) ret %d", err);
 
 	ov511->streaming = 1;
 
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.41/linux/drivers/usb/printer.c	Fri Jan 21 18:19:17 2000
+++ linux/drivers/usb/printer.c	Mon Jan 31 10:09:35 2000
@@ -125,15 +125,15 @@
 	if (status & LP_PERRORP) {
 	
 		if (status & LP_POUTPA) {
-			printk(KERN_INFO "usblp%d: out of paper", usblp->minor);
+			info("usblp%d: out of paper", usblp->minor);
 			return -ENOSPC;
 		}
 		if (~status & LP_PSELECD) {
-			printk(KERN_INFO "usblp%d: off-line", usblp->minor);
+			info("usblp%d: off-line", usblp->minor);
 			return -EIO;
 		}
 		if (~status & LP_PERRORP) {
-			printk(KERN_INFO "usblp%d: on fire", usblp->minor);
+			info("usblp%d: on fire", usblp->minor);
 			return -EIO;
 		}
 	}
@@ -229,18 +229,19 @@
 
 		if (usblp->writeurb.status == -EINPROGRESS) {
 			usb_unlink_urb(&usblp->writeurb);
-			printk(KERN_ERR "usblp%d: timed out\n", usblp->minor);
+			err("usblp%d: timed out", usblp->minor);
 			return -EIO;
 		}
 
 		if (!usblp->dev)
 			return -ENODEV;
 
-		if (!usblp->writeurb.status)
+		if (!usblp->writeurb.status) {
 			writecount += usblp->writeurb.transfer_buffer_length;
-		else {
+			usblp->writeurb.transfer_buffer_length = 0;
+		} else {
 			if (!(retval = usblp_check_status(usblp))) {
-				printk(KERN_ERR "usblp%d: error %d writing to printer\n",
+				err("usblp%d: error %d writing to printer",
 					usblp->minor, usblp->writeurb.status);
 				return -EIO;
 			}
@@ -287,7 +288,7 @@
 		return -ENODEV;
 
 	if (usblp->readurb.status) {
-		printk(KERN_ERR "usblp%d: error %d reading from printer\n",
+		err("usblp%d: error %d reading from printer",
 			usblp->minor, usblp->readurb.status);
 		usb_submit_urb(&usblp->readurb);
 		return -EIO;
@@ -389,7 +390,7 @@
 			buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
 	}
 
-	printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d if %d alt %d\n",
+	info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
 		minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
 
 	return usblp_table[minor] = usblp;
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.3.41/linux/drivers/usb/scanner.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/scanner.c	Mon Jan 31 10:09:41 2000
@@ -331,7 +331,6 @@
 	
 	int ep_cnt;
 
-	char *ident;
 	char valid_device = 0;
 	char have_bulk_in, have_bulk_out, have_intr;
 
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/uhci-debug.h linux/drivers/usb/uhci-debug.h
--- v2.3.41/linux/drivers/usb/uhci-debug.h	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/uhci-debug.h	Mon Jan 31 10:10:07 2000
@@ -1,195 +1,260 @@
-#ifdef DEBUG
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * Kernel visible pointers are surrounded in []'s and bus
+ * visible pointers are surrounded in ()'s
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ */
 
-static void uhci_show_qh (puhci_desc_t qh)
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "uhci.h"
+
+void uhci_show_td(struct uhci_td * td)
 {
-	if (qh->type != QH_TYPE) {
-		dbg("qh has not QH_TYPE");
-		return;
+	char *spid;
+
+	printk("%08x ", td->link);
+	printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+		((td->status >> 27) & 3),
+		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
+		(td->status & TD_CTRL_LS) ?       "LS " : "",
+		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
+		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
+		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
+		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
+		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
+		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
+		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
+		td->status & 0x7ff);
+
+	switch (td->info & 0xff) {
+		case USB_PID_SETUP:
+			spid = "SETUP";
+			break;
+		case USB_PID_OUT:
+			spid = "OUT";
+			break;
+		case USB_PID_IN:
+			spid = "IN";
+			break;
+		default:
+			spid = "?";
+			break;
 	}
-	dbg("uhci_show_qh %p (%08lX):", qh, virt_to_bus (qh));
 
-	if (qh->hw.qh.head & UHCI_PTR_TERM)
-		dbg("Head Terminate");
-	else {
-		if (qh->hw.qh.head & UHCI_PTR_QH)
-			dbg("Head points to QH");
-		else
-			dbg("Head points to TD");
+	printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
+		td->info >> 21,
+		((td->info >> 19) & 1),
+		(td->info >> 15) & 15,
+		(td->info >> 8) & 127,
+		(td->info & 0xff),
+		spid);
+	printk("(buf=%08x)\n", td->buffer);
+}
 
-		dbg("head: %08X", qh->hw.qh.head & ~UHCI_PTR_BITS);
-	}
-	if (qh->hw.qh.element & UHCI_PTR_TERM)
-		dbg("Element Terminate");
-	else {
+static void uhci_show_sc(int port, unsigned short status)
+{
+	printk("  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+		port,
+		status,
+		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+		(status & USBPORTSC_PR) ?   "PortReset " : "",
+		(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+		(status & USBPORTSC_RD) ?   "ResumeDetect " : "",
+		(status & USBPORTSC_PEC) ?  "EnableChange " : "",
+		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
+		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
+		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
+}
 
-		if (qh->hw.qh.element & UHCI_PTR_QH)
-			dbg("Element points to QH");
-		else
-			dbg("Element points to TD");
-		dbg("element: %08X", qh->hw.qh.element & ~UHCI_PTR_BITS);
-	}
+void uhci_show_status(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	usbcmd    = inw(io_addr + 0);
+	usbstat   = inw(io_addr + 2);
+	usbint    = inw(io_addr + 4);
+	usbfrnum  = inw(io_addr + 6);
+	flbaseadd = inl(io_addr + 8);
+	sof       = inb(io_addr + 12);
+	portsc1   = inw(io_addr + 16);
+	portsc2   = inw(io_addr + 18);
+
+	printk("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+		usbcmd,
+		(usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
+		(usbcmd & USBCMD_CF) ?      "CF " : "",
+		(usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
+		(usbcmd & USBCMD_FGR) ?     "FGR " : "",
+		(usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
+		(usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
+		(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+		(usbcmd & USBCMD_RS) ?      "RS " : "");
+
+	printk("  usbstat   =     %04x   %s%s%s%s%s%s\n",
+		usbstat,
+		(usbstat & USBSTS_HCH) ?    "HCHalted " : "",
+		(usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
+		(usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
+		(usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
+		(usbstat & USBSTS_ERROR) ?  "USBError " : "",
+		(usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+	printk("  usbint    =     %04x\n", usbint);
+	printk("  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
+		0xfff & (4*(unsigned int)usbfrnum));
+	printk("  flbaseadd = %08x\n", flbaseadd);
+	printk("  sof       =       %02x\n", sof);
+	uhci_show_sc(1, portsc1);
+	uhci_show_sc(2, portsc2);
 }
-#endif
 
-static void uhci_show_td (puhci_desc_t td)
+#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
+
+struct uhci_td *uhci_link_to_td(unsigned int link)
 {
-	char *spid;
-	warn("uhci_show_td %p (%08lX) ", td, virt_to_bus (td));
+	if (link & UHCI_PTR_TERM)
+		return NULL;
 
-	switch (td->hw.td.info & 0xff) {
-	case USB_PID_SETUP:
-		spid = "SETUP";
-		break;
-	case USB_PID_OUT:
-		spid = " OUT ";
-		break;
-	case USB_PID_IN:
-		spid = " IN  ";
-		break;
-	default:
-		spid = "  ?  ";
-		break;
-	}
-
-	warn("MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)",
-	     td->hw.td.info >> 21,
-	     ((td->hw.td.info >> 19) & 1),
-	     (td->hw.td.info >> 15) & 15,
-	     (td->hw.td.info >> 8) & 127,
-	     (td->hw.td.info & 0xff),
-	     spid,
-	     td->hw.td.buffer);
-
-	warn("Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
-	     td->hw.td.status & 0x7ff,
-	     ((td->hw.td.status >> 27) & 3),
-	     (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
-	     (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
-	     (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
-	     (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
-	     (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
-	     (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
-	     (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
-	     (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
-	     (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
-	     (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
-		);
-#if 1
-	if (td->hw.td.link & UHCI_PTR_TERM)
-		warn("Link Terminate");
-	else {
-		if (td->hw.td.link & UHCI_PTR_QH)
-			warn("%s, link points to QH @ %08x",
-			     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
-			     td->hw.td.link & ~UHCI_PTR_BITS);
-		else
-			warn("%s, link points to TD @ %08x",
-			     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
-			     td->hw.td.link & ~UHCI_PTR_BITS);
-	}
-#endif
-}
-#ifdef DEBUG
-static void uhci_show_td_queue (puhci_desc_t td)
-{
-	dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td));
-	while (1) {
-		uhci_show_td (td);
-		if (td->hw.td.link & UHCI_PTR_TERM)
-			break;
-		//if(!(td->hw.td.link&UHCI_PTR_DEPTH))
-		//      break;
-		if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
-			td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
-		else {
-			dbg("td points to itself!");
-			break;
-		}
-//              schedule();
-	}
+	return bus_to_virt(link & ~UHCI_PTR_BITS);
 }
 
-static void uhci_show_queue (puhci_desc_t qh)
+void uhci_show_queue(struct uhci_qh *qh)
 {
-	dbg("uhci_show_queue %p:", qh);
-	while (1) {
-		uhci_show_qh (qh);
+	struct uhci_td *td, *first;
+	int i = 0, count = 1000;
 
-		if (qh->hw.qh.element & UHCI_PTR_QH)
-			dbg("Warning: qh->element points to qh!");
-		else if (!(qh->hw.qh.element & UHCI_PTR_TERM))
-			uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+	if (qh->element & UHCI_PTR_QH)
+		printk("      Element points to QH (bug?)\n");
 
-		if (qh->hw.qh.head & UHCI_PTR_TERM)
-			break;
+	if (qh->element & UHCI_PTR_DEPTH)
+		printk("      Depth traverse\n");
 
-		if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
-			qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
-		else {
-			dbg("qh points to itself!");
+	if (qh->element & UHCI_PTR_TERM)
+		printk("      Terminate\n");
+
+	if (!(qh->element & ~UHCI_PTR_BITS)) {
+		printk("      td 0: [NULL]\n");
+		return;
+	}
+
+	first = uhci_link_to_td(qh->element);
+
+	/* Make sure it doesn't runaway */
+	for (td = first; td && count > 0; 
+	     td = uhci_link_to_td(td->link), --count) {
+		printk("      td %d: [%p]\n", i++, td);
+		printk("      ");
+		uhci_show_td(td);
+
+		if (td == uhci_link_to_td(td->link)) {
+			printk(KERN_ERR "td links to itself!\n");
 			break;
 		}
 	}
 }
 
-static void uhci_show_sc (int port, unsigned short status)
+static int uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
 {
-	dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
-	     port,
-	     status,
-	     (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
-	     (status & USBPORTSC_PR) ? "PortReset " : "",
-	     (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
-	     (status & USBPORTSC_RD) ? "ResumeDetect " : "",
-	     (status & USBPORTSC_PEC) ? "EnableChange " : "",
-	     (status & USBPORTSC_PE) ? "PortEnabled " : "",
-	     (status & USBPORTSC_CSC) ? "ConnectChange " : "",
-	     (status & USBPORTSC_CCS) ? "PortConnected " : "");
+	int j;
+
+	for (j = 0; j < UHCI_NUM_SKELTD; j++)
+		if (td == uhci->skeltd + j)
+			return 1;
+
+	return 0;
 }
 
-void uhci_show_status (puhci_t s)
+static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
-	unsigned int io_addr = s->io_addr;
-	unsigned short usbcmd, usbstat, usbint, usbfrnum;
-	unsigned int flbaseadd;
-	unsigned char sof;
-	unsigned short portsc1, portsc2;
+	int j;
+
+	for (j = 0; j < UHCI_NUM_SKELQH; j++)
+		if (qh == uhci->skelqh + j)
+			return 1;
 
-	usbcmd = inw (io_addr + 0);
-	usbstat = inw (io_addr + 2);
-	usbint = inw (io_addr + 4);
-	usbfrnum = inw (io_addr + 6);
-	flbaseadd = inl (io_addr + 8);
-	sof = inb (io_addr + 12);
-	portsc1 = inw (io_addr + 16);
-	portsc2 = inw (io_addr + 18);
-
-	dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
-	     usbcmd,
-	     (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
-	     (usbcmd & USBCMD_CF) ? "CF " : "",
-	     (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
-	     (usbcmd & USBCMD_FGR) ? "FGR " : "",
-	     (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
-	     (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
-	     (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
-	     (usbcmd & USBCMD_RS) ? "RS " : "");
-
-	dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
-	     usbstat,
-	     (usbstat & USBSTS_HCH) ? "HCHalted " : "",
-	     (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
-	     (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
-	     (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
-	     (usbstat & USBSTS_ERROR) ? "USBError " : "",
-	     (usbstat & USBSTS_USBINT) ? "USBINT " : "");
-
-	dbg("  usbint    =     %04x", usbint);
-	dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
-	     0xfff & (4 * (unsigned int) usbfrnum));
-	dbg("  flbaseadd = %08x", flbaseadd);
-	dbg("  sof       =       %02x", sof);
-	uhci_show_sc (1, portsc1);
-	uhci_show_sc (2, portsc2);
+	return 0;
 }
-#endif
+
+static const char *td_names[] = {"interrupt1", "interrupt2", "interrupt4",
+				 "interrupt8", "interrupt16", "interrupt32",
+				 "interrupt64", "interrupt128", "interrupt256" };
+static const char *qh_names[] = { "control", "bulk" };
+
+void uhci_show_queues(struct uhci *uhci)
+{
+	int i, isqh;
+	struct uhci_qh *qh;
+	struct uhci_td *td;
+
+	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+		int shown = 0;
+
+		td = uhci_link_to_td(uhci->fl->frame[i]);
+		if (td)
+			isqh = uhci->fl->frame[i] & UHCI_PTR_QH;
+		while (td && !isqh) {
+			if (uhci_is_skeleton_td(uhci, td))
+				break;
+
+			if (!shown) {
+				printk("   Frame %d\n", i);
+				shown = 1;
+			}
+
+			printk("[%p] ", td);
+
+			uhci_show_td(td);
+			td = uhci_link_to_td(td->link);
+			if (td)
+				isqh = td->link & UHCI_PTR_QH;
+		}
+	}
+	for (i = 0; i < UHCI_NUM_SKELTD; ++i) {
+		printk("  %s: [%p] (%08x)\n", td_names[i],
+			&uhci->skeltd[i],
+			uhci->skeltd[i].link);
+
+		td = uhci_link_to_td(uhci->skeltd[i].link);
+		if (td)
+			isqh = uhci->skeltd[i].link & UHCI_PTR_QH;
+		while (td && !isqh) {
+			if (uhci_is_skeleton_td(uhci, td))
+				break;
+
+			printk("[%p] ", td);
+
+			uhci_show_td(td);
+			td = uhci_link_to_td(td->link);
+			if (td)
+				isqh = td->link & UHCI_PTR_QH;
+		}
+	}
+	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+		printk("  %s: [%p] (%08x) (%08x)\n", qh_names[i],
+			&uhci->skelqh[i],
+			uhci->skelqh[i].link, uhci->skelqh[i].element);
+
+		qh = uhci_link_to_qh(uhci->skelqh[i].link);
+		for (; qh; qh = uhci_link_to_qh(qh->link)) {
+			if (uhci_is_skeleton_qh(uhci, qh))
+				break;
+
+			printk("    [%p] (%08x) (%08x)\n",
+				qh, qh->link, qh->element);
+
+			uhci_show_queue(qh);
+		}
+	}
+}
+
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.41/linux/drivers/usb/uhci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/uhci.c	Mon Jan 31 16:42:02 2000
@@ -0,0 +1,2214 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@sventech.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#define DEBUG
+#include "usb.h"
+
+#include "uhci.h"
+#include "uhci-debug.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+#endif
+
+static int debug = 1;
+MODULE_PARM(debug, "i");
+
+static kmem_cache_t *uhci_td_cachep;
+static kmem_cache_t *uhci_qh_cachep;
+
+static LIST_HEAD(uhci_list);
+
+static int rh_submit_urb(urb_t *urb);
+static int rh_unlink_urb(urb_t *urb);
+static int uhci_get_current_frame_number(struct usb_device *usb_dev);
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+static int uhci_alloc_dev(struct usb_device *usb_dev)
+{
+	struct uhci_device *dev;
+
+	/* Allocate the UHCI 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->uhci = usb_to_uhci(usb_dev->parent)->uhci;
+
+	return 0;
+}
+
+static int uhci_free_dev(struct usb_device *usb_dev)
+{
+	struct uhci_device *dev = usb_to_uhci(usb_dev);
+
+	if (atomic_dec_and_test(&dev->refcnt))
+		kfree(dev);
+
+	return 0;
+}
+
+static void uhci_inc_dev_use(struct uhci_device *dev)
+{
+	atomic_inc(&dev->refcnt);
+}
+
+static void uhci_dec_dev_use(struct uhci_device *dev)
+{
+	uhci_free_dev(dev->usb);
+}
+
+/*
+ * UHCI interrupt list operations..
+ */
+static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	nested_lock(&uhci->irqlist_lock, flags);
+	list_add(&td->irq_list, &uhci->interrupt_list);
+	nested_unlock(&uhci->irqlist_lock, flags);
+}
+
+static void uhci_remove_irq_list(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	nested_lock(&uhci->irqlist_lock, flags);
+	if (td->irq_list.next != &td->irq_list) {
+		list_del(&td->irq_list);
+		INIT_LIST_HEAD(&td->irq_list);
+	}
+	nested_unlock(&uhci->irqlist_lock, flags);
+}
+
+static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->urblist_lock, flags);
+	list_add(&urb->urb_list, &uhci->urb_list);
+	spin_unlock_irqrestore(&uhci->urblist_lock, flags);
+}
+
+static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->urblist_lock, flags);
+	if (urb->urb_list.next != &urb->urb_list) {
+		list_del(&urb->urb_list);
+		INIT_LIST_HEAD(&urb->urb_list);
+	}
+	spin_unlock_irqrestore(&uhci->urblist_lock, flags);
+}
+
+/*
+ * We insert Isochronous transfers directly into the frame list at the
+ * beginning
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) ->
+ * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
+ */
+
+static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+	unsigned long flags;
+	struct uhci_td *nexttd;
+
+	framenum %= UHCI_NUMFRAMES;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	td->frameptr = &uhci->fl->frame[framenum];
+	td->link = uhci->fl->frame[framenum];
+	if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+		nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
+		td->nexttd = nexttd;
+		nexttd->prevtd = td;
+		nexttd->frameptr = NULL;
+	}
+	uhci->fl->frame[framenum] = virt_to_bus(td);
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	if (td->frameptr) {
+		*(td->frameptr) = td->link;
+		if (td->nexttd) {
+			td->nexttd->frameptr = td->frameptr;
+			td->nexttd->prevtd = NULL;
+			td->nexttd = NULL;
+		}
+		td->frameptr = NULL;
+	} else {
+		if (td->prevtd) {
+			td->prevtd->nexttd = td->nexttd;
+			td->prevtd->link = td->link;
+		}
+		if (td->nexttd)
+			td->nexttd->prevtd = td->prevtd;
+		td->prevtd = td->nexttd = NULL;
+	}
+	td->link = UHCI_PTR_TERM;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+	/* Fix the linked list pointers */
+	td->nexttd = skeltd->nexttd;
+	td->prevtd = skeltd;
+	if (skeltd->nexttd)
+		skeltd->nexttd->prevtd = td;
+	skeltd->nexttd = td;
+
+	td->link = skeltd->link;
+	skeltd->link = virt_to_bus(td);
+
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+/*
+ * Inserts a td into qh list at the top.
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *begin)
+{
+	struct uhci_td *td, *prevtd;
+
+	if (!begin)		/* Nothing to do */
+		return;
+
+	/* Grab the first TD and add it to the QH */
+	td = begin;
+	qh->element = virt_to_bus(td) | UHCI_PTR_DEPTH;
+
+	/* Go through the rest of the TD's, link them together */
+	prevtd = td;
+	td = td->next;
+	while (td) {
+		prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
+
+		prevtd = td;
+		td = td->next;
+	}
+
+	prevtd->link = UHCI_PTR_TERM;
+}
+
+static struct uhci_td *uhci_td_alloc(struct uhci_device *dev)
+{
+	struct uhci_td *td;
+
+	td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	if (!td)
+		return NULL;
+
+	td->link = UHCI_PTR_TERM;
+	td->buffer = 0;
+
+	td->frameptr = NULL;
+	td->nexttd = td->prevtd = NULL;
+	td->next = NULL;
+	td->dev = dev;
+	INIT_LIST_HEAD(&td->irq_list);
+	INIT_LIST_HEAD(&td->list);
+
+	uhci_inc_dev_use(dev);
+
+	return td;
+}
+
+static void uhci_td_free(struct uhci_td *td)
+{
+	kmem_cache_free(uhci_td_cachep, td);
+
+	if (td->dev)
+		uhci_dec_dev_use(td->dev);
+}
+
+static void uhci_schedule_delete_td(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->freelist_lock, flags);
+	list_add(&td->list, &uhci->td_free_list);
+	if (td->dev) {
+		uhci_dec_dev_use(td->dev);
+		td->dev = NULL;
+	}
+	spin_unlock_irqrestore(&uhci->freelist_lock, flags);
+}
+
+static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev)
+{
+	struct uhci_qh *qh;
+
+	qh = kmem_cache_alloc(uhci_qh_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	if (!qh)
+		return NULL;
+
+	qh->element = UHCI_PTR_TERM;
+	qh->link = UHCI_PTR_TERM;
+
+	qh->dev = dev;
+	qh->prevqh = qh->nextqh = NULL;
+
+	INIT_LIST_HEAD(&qh->list);
+
+	uhci_inc_dev_use(dev);
+
+	return qh;
+}
+
+static void uhci_qh_free(struct uhci_qh *qh)
+{
+	kmem_cache_free(uhci_qh_cachep, qh);
+
+	if (qh->dev)
+		uhci_dec_dev_use(qh->dev);
+}
+
+static void uhci_schedule_delete_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->freelist_lock, flags);
+	list_add(&qh->list, &uhci->qh_free_list);
+	if (qh->dev) {
+		uhci_dec_dev_use(qh->dev);
+		qh->dev = NULL;
+	}
+	spin_unlock_irqrestore(&uhci->freelist_lock, flags);
+}
+
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+	/* Fix the linked list pointers */
+	qh->nextqh = skelqh->nextqh;
+	qh->prevqh = skelqh;
+	if (skelqh->nextqh)
+		skelqh->nextqh->prevqh = qh;
+	skelqh->nextqh = qh;
+
+	qh->link = skelqh->link;
+	skelqh->link = virt_to_bus(qh) | UHCI_PTR_QH;
+
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	if (qh->prevqh) {
+		qh->prevqh->nextqh = qh->nextqh;
+		qh->prevqh->link = qh->link;
+	}
+	if (qh->nextqh)
+		qh->nextqh->prevqh = qh->prevqh;
+	qh->prevqh = qh->nextqh = NULL;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
+		__u32 info, __u32 buffer)
+{
+	td->status = status;
+	td->info = info;
+	td->buffer = buffer;
+}
+
+static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	td->urb = urb;
+
+	if (urbp->end)
+		urbp->end->next = td;
+
+	urbp->end = td;
+
+	if (!urbp->begin)
+		urbp->begin = td;
+}
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+static int uhci_map_status(int status, int dir_out)
+{
+	if (!status)
+		return 0;
+	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */
+		return -EPROTO;
+	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
+		if (dir_out)
+			return -ETIMEDOUT;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_NAK)			/* NAK */
+		return -ETIMEDOUT;
+	if (status & TD_CTRL_BABBLE)			/* Babble */
+		return -EPIPE;
+	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
+		return -ENOSR;
+	if (status & TD_CTRL_STALLED)			/* Stalled */
+		return -EPIPE;
+	if (status & TD_CTRL_ACTIVE)			/* Active */
+		return 0;
+
+	return -EINVAL;
+}
+
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(urb_t *urb)
+{
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	struct uhci_device *dev = usb_to_uhci(urb->dev);
+	struct uhci *uhci = dev->uhci;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	unsigned char *data = urb->transfer_buffer;
+	struct urb_priv *urbp;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+
+	urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!urbp)
+		return -ENOMEM;
+
+	urbp->begin = urbp->end = NULL;
+
+	urb->hcpriv = urbp;
+
+	/*
+	 * Build the TD for the control request
+	 */
+	td = uhci_td_alloc(dev);
+	if (!td)
+		return -ENOMEM;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination | (7 << 21),
+		virt_to_bus(urb->setup_packet));
+
+	/*
+	 * If direction is "send", change the frame from SETUP (0x2D)
+	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
+	 */
+	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
+
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		status |= TD_CTRL_SPD;
+
+	/*
+	 * Build the DATA TD's
+	 */
+	td = uhci_td_alloc(dev);
+	if (!td) {
+		/* FIXME: Free the TD's */
+		return -ENOMEM;
+	}
+
+	while (len > 0) {
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		/* Alternate Data0/1 (start with Data1) */
+		destination ^= 1 << TD_TOKEN_TOGGLE;
+	
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
+			virt_to_bus(data));
+
+		data += pktsze;
+		len -= pktsze;
+
+		td = uhci_td_alloc(dev);
+		if (!td)
+			/* FIXME: Free all of the previously allocated td's */
+			return -ENOMEM;
+	}
+
+	/*
+	 * Build the final TD for control status 
+	 *
+	 * It's IN if the pipe is an output pipe or we're not expecting
+	 * data back.
+	 */
+	destination &= ~TD_PID;
+	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= 1 << TD_TOKEN_TOGGLE;		/* End in Data1 */
+
+	status &= ~TD_CTRL_SPD;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status | TD_CTRL_IOC,
+		destination | (UHCI_NULL_DATA_SIZE << 21), 0);
+
+	uhci_add_irq_list(uhci, td);
+
+	qh = uhci_qh_alloc(dev);
+	if (!qh) {
+		/* FIXME: Free all of the TD's */
+		return -ENOMEM;
+	}
+	uhci_insert_tds_in_qh(qh, urbp->begin);
+
+	uhci_insert_qh(uhci, &uhci->skel_control_qh, qh);
+	urbp->qh = qh;
+
+	uhci_add_urb_list(uhci, urb);
+
+	usb_inc_dev_use(urb->dev);
+
+	return -EINPROGRESS;
+}
+
+static int uhci_unlink_control(urb_t *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	struct uhci_device *dev = usb_to_uhci(urb->dev);
+	struct uhci *uhci = dev->uhci;
+
+	if (!urbp)
+		return -EINVAL;
+
+	uhci_remove_qh(uhci, urbp->qh);
+	uhci_schedule_delete_qh(uhci, urbp->qh);
+
+	/* Go through the rest of the TD's, deleting them, then scheduling */
+	/*  their deletion */
+	td = urbp->begin;
+	while (td) {
+		struct uhci_td *next = td->next;
+
+		if (td->status & TD_CTRL_IOC)
+			uhci_remove_irq_list(uhci, td);
+
+		uhci_schedule_delete_td(uhci, td);
+
+		td = next;
+	}
+
+	kfree(urbp);
+	urb->hcpriv = NULL;
+
+	uhci_remove_urb_list(uhci, urb);
+
+	return 0;
+}
+
+static int uhci_result_control(urb_t *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret;
+
+	td = urbp->begin;
+	if (!td)		/* Nothing to do */
+		return -EINVAL;
+
+	/* The first TD is the SETUP phase, check the status, but skip */
+	/*  the count */
+	status =  uhci_status_bits(td->status);
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	urb->actual_length = 0;
+
+	/* The rest of the TD's (but the last) are data */
+	td = td->next;
+	while (td && td->next) {
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		/* If SPD is set then we received a short packet */
+		/*  There will be no status phase at the end */
+		if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
+			goto td_success;
+
+		if (status)
+			goto td_error;
+
+		td = td->next;
+	}
+
+	/* Control status phase */
+	status = uhci_status_bits(td->status);
+
+	/* APC BackUPS Pro kludge */
+	/* It tries to send all of the descriptor instead of */
+	/*  the amount we requested */
+	if (td->status & TD_CTRL_IOC &&
+	    status & TD_CTRL_ACTIVE &&
+	    status & TD_CTRL_NAK)
+		goto td_success;
+
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+td_success:
+	uhci_unlink_control(urb);
+
+	return 0;
+
+td_error:
+	/* Some debugging code */
+	if (debug) {
+		dbg("uhci_result_control() failed with status %x",
+			status);
+
+		/* Print the chain for debugging purposes */
+		uhci_show_queue(urbp->qh);
+	}
+
+	if (status & TD_CTRL_STALLED) {
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+		uhci_unlink_control(urb);
+
+		return -EPIPE;
+	}
+
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+
+	uhci_unlink_control(urb);
+
+	return ret;
+}
+
+/*
+ * Interrupt transfers
+ */
+static int uhci_submit_interrupt(urb_t *urb)
+{
+	struct uhci_td *td;
+	unsigned long destination, status;
+	struct uhci_device *dev = usb_to_uhci(urb->dev);
+	struct uhci *uhci = dev->uhci;
+	struct urb_priv *urbp;
+
+	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD |
+			TD_CTRL_IOC;
+
+	urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!urbp)
+		return -ENOMEM;
+
+	urbp->begin = urbp->end = NULL;
+
+	urb->hcpriv = urbp;
+
+	td = uhci_td_alloc(dev);
+	if (!td)
+		return -ENOMEM;
+
+	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+	destination |= ((urb->transfer_buffer_length - 1) << 21);
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination,
+		virt_to_bus(urb->transfer_buffer));
+
+	uhci_add_irq_list(uhci, td);
+
+	uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td);
+
+	uhci_add_urb_list(uhci, urb);
+
+	usb_inc_dev_use(urb->dev);
+
+	return -EINPROGRESS;
+}
+
+static int uhci_unlink_interrupt(urb_t *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	struct uhci_device *dev = usb_to_uhci(urb->dev);
+	struct uhci *uhci = dev->uhci;
+
+	if (!urbp)
+		return -EINVAL;
+
+	td = urbp->begin;
+	uhci_remove_td(uhci, td);
+	if (td->status & TD_CTRL_IOC)
+		uhci_remove_irq_list(uhci, td);
+	uhci_schedule_delete_td(uhci, td);
+
+	kfree(urbp);
+	urb->hcpriv = NULL;
+
+	uhci_remove_urb_list(uhci, urb);
+
+	return 0;
+}
+
+static int uhci_result_interrupt(urb_t *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	int status;
+
+	if (!urbp)
+		return -EINVAL;
+
+	td = urbp->begin;
+	if (!td)
+		return -EINVAL;
+
+	status =  uhci_status_bits(td->status);
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		return uhci_map_status(status, uhci_packetout(td->info));
+
+	urb->actual_length += uhci_actual_length(td->status);
+
+	return 0;
+}
+
+static void uhci_reset_interrupt(urb_t *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+
+	if (urb->interval) {
+		td = urbp->begin;
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+		td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+		td->info &= ~(1 << TD_TOKEN_TOGGLE);
+		td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+
+		urb->status = -EINPROGRESS;
+	} else
+		uhci_unlink_interrupt(urb);
+}
+
+/*
+ * Bulk transfers
+ */
+static int uhci_submit_bulk(urb_t *urb)
+{
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	struct uhci_device *dev = usb_to_uhci(urb->dev);
+	struct uhci *uhci = dev->uhci;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	unsigned char *data = urb->transfer_buffer;
+	struct urb_priv *urbp;
+
+	if (len < 0)
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		status |= TD_CTRL_SPD;
+
+	urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!urbp)
+		return -ENOMEM;
+
+	urbp->begin = urbp->end = NULL;
+
+	urb->hcpriv = urbp;
+
+	/*
+	 * Build the DATA TD's
+	 */
+	while (len > 0) {
+		int pktsze = len;
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td = uhci_td_alloc(dev);
+		if (!td) {
+			/* FIXME: Free the TD's */
+			return -ENOMEM;
+		}
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+			virt_to_bus(data));
+
+		data += pktsze;
+		len -= maxsze;
+
+		if (len <= 0) {
+			td->status |= TD_CTRL_IOC;
+			uhci_add_irq_list(uhci, td);
+		}
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	}
+
+	qh = uhci_qh_alloc(dev);
+	if (!qh) {
+		/* FIXME: Free all of the TD's */
+		return -ENOMEM;
+	}
+	uhci_insert_tds_in_qh(qh, urbp->begin);
+
+	uhci_insert_qh(dev->uhci, &dev->uhci->skel_bulk_qh, qh);
+	urbp->qh = qh;
+
+	uhci_add_urb_list(uhci, urb);
+
+	usb_inc_dev_use(urb->dev);
+
+	return -EINPROGRESS;
+}
+
+/* We can use the control unlink since they're identical */
+#define uhci_unlink_bulk uhci_unlink_control
+
+static int uhci_result_bulk(urb_t *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+
+	urb->actual_length = 0;
+
+	/* The rest of the TD's (but the last) are data */
+	for (td = urbp->begin; td; td = td->next) {
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		/* If SPD is set then we received a short packet */
+		if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info))) {
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info) ^ 1);
+
+			goto td_success;
+		}
+
+		if (status)
+			goto td_error;
+	}
+
+td_success:
+	uhci_unlink_bulk(urb);
+
+	return 0;
+
+td_error:
+	/* Some debugging code */
+	if (debug) {
+		dbg("uhci_result_bulk() failed with status %x",
+			status);
+
+		/* Print the chain for debugging purposes */
+		uhci_show_queue(urbp->qh);
+	}
+
+	if (status & TD_CTRL_STALLED) {
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+		return -EPIPE;
+	}
+
+	return uhci_map_status(status, uhci_packetout(td->info));
+}
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int *end)
+{
+	urb_t *u, *last_urb = NULL;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct list_head *tmp, *head = &uhci->urb_list;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->urblist_lock, flags);
+	tmp = head->next;
+	while (tmp != head) {
+		u = list_entry(tmp, urb_t, urb_list);
+
+		/* look for pending URB's with identical pipe handle */
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+		    (u->status == -EINPROGRESS) && (u != urb)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+		tmp = tmp->next;
+	}
+	spin_unlock_irqrestore(&uhci->urblist_lock, flags);
+
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+		return 0;
+	} else
+		return -1;	// no previous urb found
+
+}
+
+static int isochronous_find_start(urb_t *urb)
+{
+	int limits;
+	unsigned int start = 0, end = 0;
+
+	if (urb->number_of_packets > 900)	/* 900? Why? */
+		return -EFBIG;
+
+	limits = isochronous_find_limits(urb, &start, &end);
+
+	if (urb->transfer_flags & USB_ISO_ASAP) {
+		if (limits) {
+			int curframe;
+
+			curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
+			urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
+		} else
+			urb->start_frame = end;
+	} else {
+		urb->start_frame %= UHCI_NUMFRAMES;
+		/* FIXME: Sanity check */
+	}
+
+	return 0;
+}
+
+static int uhci_submit_isochronous(urb_t *urb)
+{
+	struct uhci_td *td;
+	struct uhci_device *dev = usb_to_uhci(urb->dev);
+	struct uhci *uhci = dev->uhci;
+	struct urb_priv *urbp;
+	int i, ret, framenum;
+	int status, destination;
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	ret = isochronous_find_start(urb);
+	if (ret)
+		return ret;
+
+	urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!urbp)
+		return -ENOMEM;
+
+	urbp->begin = urbp->end = NULL;
+
+	urb->hcpriv = urbp;
+
+	framenum = urb->start_frame;
+	for (i = 0; i < urb->number_of_packets; i++, framenum++) {
+		if (!urb->iso_frame_desc[i].length)
+			continue;
+
+		td = uhci_td_alloc(dev);
+		if (!td) {
+			/* FIXME: Free the TD's */
+			return -ENOMEM;
+		}
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
+			virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset));
+
+		if (i + 1 >= urb->number_of_packets) {
+			td->status |= TD_CTRL_IOC;
+			uhci_add_irq_list(uhci, td);
+		}
+
+		uhci_insert_td_frame_list(uhci, td, framenum);
+	}
+
+	uhci_add_urb_list(uhci, urb);
+
+	usb_inc_dev_use(urb->dev);
+
+	return -EINPROGRESS;
+}
+
+static int uhci_unlink_isochronous(urb_t *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	struct uhci_device *dev = usb_to_uhci(urb->dev);
+	struct uhci *uhci = dev->uhci;
+
+	if (!urbp)
+		return -EINVAL;
+
+	/* Go through the rest of the TD's, deleting them, then scheduling */
+	/*  their deletion */
+	td = urbp->begin;
+	while (td) {
+		struct uhci_td *next = td->next;
+
+		uhci_remove_td(uhci, td);
+
+		if (td->status & TD_CTRL_IOC)
+			uhci_remove_irq_list(uhci, td);
+		uhci_schedule_delete_td(uhci, td);
+
+		td = next;
+	}
+
+	kfree(urbp);
+	urb->hcpriv = NULL;
+
+	uhci_remove_urb_list(uhci, urb);
+
+	return 0;
+}
+
+static int uhci_result_isochronous(urb_t *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+	int status;
+	int i, ret = 0;
+
+	td = urbp->end;
+	if (!td)		/* Nothing to do */
+		return -EINVAL;
+
+	status =  uhci_status_bits(td->status);
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	/* Assume no errors, we'll overwrite this if not */
+	urb->status = 0;
+
+	urb->actual_length = 0;
+	for (i = 0, td = urbp->begin; td; i++, td = td->next) {
+		int actlength;
+
+		actlength = uhci_actual_length(td->status);
+		urb->iso_frame_desc[i].actual_length = actlength;
+		urb->actual_length += actlength;
+
+		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
+		urb->iso_frame_desc[i].status = status;
+		if (status != 0) {
+			urb->error_count++;
+			ret = status;
+		}
+	}
+
+	uhci_unlink_isochronous(urb);
+
+	return status;
+}
+
+static int uhci_submit_urb(urb_t *urb)
+{
+	int ret = -EINVAL;
+	struct uhci *uhci;
+
+	if (!urb)
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
+		return rh_submit_urb(urb);	/* Virtual root hub */
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_submit_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		ret = uhci_submit_interrupt(urb);
+		break;
+	case PIPE_BULK:
+		ret = uhci_submit_bulk(urb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_submit_isochronous(urb);
+		break;
+	}
+
+	urb->status = ret;
+	if (ret == -EINPROGRESS) {
+		usb_inc_dev_use(urb->dev);
+
+		return 0;
+	}
+
+	return ret;
+}
+
+/*
+ * Return the result of a transfer
+ */
+static void uhci_transfer_result(urb_t *urb)
+{
+	urb_t *turb;
+	int proceed = 0, is_ring = 0;
+	int ret = -EINVAL;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_result_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		/* Interrupts are an exception */
+		urb->status = uhci_result_interrupt(urb);
+		if (urb->status != -EINPROGRESS) {
+			urb->complete(urb);
+			uhci_reset_interrupt(urb);
+		}
+		return;
+	case PIPE_BULK:
+		ret = uhci_result_bulk(urb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_result_isochronous(urb);
+		break;
+	}
+
+	urb->status = ret;
+	if (urb->status == -EINPROGRESS)
+		return;
+
+	if (urb->next) {
+		turb = urb->next;
+		do {
+			if (turb->status != -EINPROGRESS) {
+				proceed = 1;
+				break;
+			}
+
+			turb = turb->next;
+		} while (turb && turb != urb && turb != urb->next);
+
+		if (turb == urb || turb == urb->next)
+			is_ring = 1;
+	}
+
+	if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
+		urb->complete(urb);
+		if (!proceed && is_ring)
+			uhci_submit_urb(urb);
+	}
+
+	if (proceed && urb->next) {
+		turb = urb->next;
+		do {
+			if (turb->status != -EINPROGRESS &&
+			    uhci_submit_urb(turb) != 0)
+
+			turb = turb->next;
+		} while (turb && turb != urb->next);
+
+		if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE))
+			urb->complete(urb);
+	}
+
+	usb_dec_dev_use(urb->dev);
+}
+
+static int uhci_unlink_urb(urb_t *urb)
+{
+	struct uhci *uhci;
+	int ret = 0;
+
+	if (!urb)
+		return -EINVAL;
+
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
+		return rh_unlink_urb(urb);
+
+	if (urb->status == -EINPROGRESS) {
+		switch (usb_pipetype(urb->pipe)) {
+		case PIPE_CONTROL:
+			ret = uhci_unlink_control(urb);
+			break;
+		case PIPE_INTERRUPT:
+			ret = uhci_unlink_interrupt(urb);
+			break;
+		case PIPE_BULK:
+			ret = uhci_unlink_bulk(urb);
+			break;
+		case PIPE_ISOCHRONOUS:
+			ret = uhci_unlink_isochronous(urb);
+			break;
+		}
+
+		if (urb->complete)
+			urb->complete(urb);
+
+		if (in_interrupt()) {		/* wait at least 1 frame */
+			int errorcount = 10;
+
+			if (errorcount--)
+				dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
+			udelay(1000);
+		} else
+			schedule_timeout(1+1*HZ/1000); 
+
+		usb_dec_dev_use(urb->dev);
+	}
+
+	urb->status = -ENOENT;
+
+	return ret;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+static int uhci_get_current_frame_number(struct usb_device *usb_dev)
+{
+	struct uhci_device *dev = (struct uhci_device *)usb_dev->hcpriv;
+
+	return inw(dev->uhci->io_addr + USBFRNUM);
+}
+
+struct usb_operations uhci_device_operations = {
+	uhci_alloc_dev,
+	uhci_free_dev,
+	uhci_get_current_frame_number,
+	uhci_submit_urb,
+	uhci_unlink_urb
+};
+
+/* -------------------------------------------------------------------
+   Virtual Root Hub
+   ------------------------------------------------------------------- */
+
+static __u8 root_hub_dev_des[] =
+{
+ 	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x00,			/*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x00,			/*  __u8  iProduct; */
+	0x00,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes;
+					Bit 7: Bus-powered, 6: Self-powered,
+					Bit 5 Remote-wakeup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,			/*  __u8  bNbrPorts; */
+	0x00,			/* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*-------------------------------------------------------------------------*/
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int rh_send_irq(urb_t *urb)
+{
+	int i, len = 1;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 data = 0;
+
+	for (i = 0; i < uhci->rh.numports; i++) {
+		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+		len = (i + 1) / 8 + 1;
+	}
+
+	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
+	urb->actual_length = len;
+	urb->status = USB_ST_NOERROR;
+
+	if ((data > 0) && (uhci->rh.send != 0)) {
+#ifdef DEBUG /* JE */
+static int foo=5;
+if (foo--)
+#endif
+		dbg("root-hub INT complete: port1: %x port2: %x data: %x",
+			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
+		urb->complete(urb);
+	}
+
+	return USB_ST_NOERROR;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+static int rh_init_int_timer(urb_t *urb);
+
+static void rh_int_timer_do(unsigned long ptr)
+{
+	int len;
+	urb_t *urb = (urb_t *)ptr;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (uhci->rh.send) {
+		len = rh_send_irq(urb);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb->complete)
+				urb->complete(urb);
+		}
+	}
+
+	rh_init_int_timer(urb);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Root Hub INTs are polled by this timer */
+static int rh_init_int_timer(urb_t *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	uhci->rh.interval = urb->interval;
+	init_timer(&uhci->rh.rh_int_timer);
+	uhci->rh.rh_int_timer.function = rh_int_timer_do;
+	uhci->rh.rh_int_timer.data = (unsigned long)urb;
+	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer(&uhci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#define OK(x)			len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) & ~(x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) | (x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+
+/*-------------------------------------------------------------------------*/
+/*************************
+ ** Root Hub Control Pipe
+ *************************/
+
+static int rh_submit_urb(urb_t *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	struct uhci *uhci = (struct uhci *)usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	devrequest *cmd = (devrequest *)urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = 0;
+	int stat = USB_ST_NOERROR;
+	int i;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 cstatus;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
+		uhci->rh.urb = urb;
+		uhci->rh.send = 1;
+		uhci->rh.interval = urb->interval;
+		rh_init_int_timer(urb);
+
+		return USB_ST_NOERROR;
+	}
+
+	bmRType_bReq = cmd->requesttype | cmd->request << 8;
+	wValue = le16_to_cpu(cmd->value);
+	wIndex = le16_to_cpu(cmd->index);
+	wLength = le16_to_cpu(cmd->length);
+
+	for (i = 0; i < 8; i++)
+		uhci->rh.c_p_r[i] = 0;
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device,
+		   RH_INTERFACE: interface,
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here,
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+		*/
+
+	case RH_GET_STATUS:
+		*(__u16 *)data = cpu_to_le16(1);
+		OK(2);
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *)data = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *)data = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *)data = cpu_to_le32(0);
+		OK(4);		/* hub power */
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+			((status & USBPORTSC_PEC) >> (3 - 1)) |
+			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+			status = (status & USBPORTSC_CCS) |
+			((status & USBPORTSC_PE) >> (2 - 1)) |
+			((status & USBPORTSC_SUSP) >> (12 - 2)) |
+			((status & USBPORTSC_PR) >> (9 - 4)) |
+			(1 << 8) |      /* power on */
+			((status & USBPORTSC_LSDA) << (-8 + 9));
+
+		*(__u16 *)data = cpu_to_le16(status);
+		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);
+		OK(4);
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case RH_ENDPOINT_STALL:
+			OK(0);
+		}
+		break;
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_OVER_CURRENT:
+			OK(0);	/* hub power over current */
+		}
+		break;
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_PORT_ENABLE:
+			CLR_RH_PORTSTAT(USBPORTSC_PE);
+			OK(0);
+		case RH_PORT_SUSPEND:
+			CLR_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0);	/* port power */
+		case RH_C_PORT_CONNECTION:
+			SET_RH_PORTSTAT(USBPORTSC_CSC);
+			OK(0);
+		case RH_C_PORT_ENABLE:
+			SET_RH_PORTSTAT(USBPORTSC_PEC);
+			OK(0);
+		case RH_C_PORT_SUSPEND:
+			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK(0);
+		case RH_C_PORT_OVER_CURRENT:
+			OK(0);	/* port power over current */
+		case RH_C_PORT_RESET:
+			uhci->rh.c_p_r[wIndex - 1] = 0;
+			OK(0);
+		}
+		break;
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_PORT_SUSPEND:
+			SET_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_RESET:
+			SET_RH_PORTSTAT(USBPORTSC_PR);
+			wait_ms(10);
+			uhci->rh.c_p_r[wIndex - 1] = 1;
+			CLR_RH_PORTSTAT(USBPORTSC_PR);
+			udelay(10);
+			SET_RH_PORTSTAT(USBPORTSC_PE);
+			wait_ms(10);
+			SET_RH_PORTSTAT(0xa);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0); /* port power ** */
+		case RH_PORT_ENABLE:
+			SET_RH_PORTSTAT (USBPORTSC_PE);
+			OK(0);
+		}
+		break;
+	case RH_SET_ADDRESS:
+		uhci->rh.devnum = wValue;
+		OK(0);
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case 0x01:	/* device descriptor */
+			len = min(leni, min(sizeof(root_hub_dev_des), wLength));
+			memcpy(data, root_hub_dev_des, len);
+			OK(len);
+		case 0x02:	/* configuration descriptor */
+			len = min(leni, min(sizeof(root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK(len);
+		case 0x03:	/* string descriptors */
+			stat = -EPIPE;
+		}
+		break;
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = uhci->rh.numports;
+		len = min(leni, min(sizeof(root_hub_hub_des), wLength));
+		memcpy(data, root_hub_hub_des, len);
+		OK(len);
+	case RH_GET_CONFIGURATION:
+		*(__u8 *)data = 0x01;
+		OK(1);
+	case RH_SET_CONFIGURATION:
+		OK(0);
+	default:
+		stat = -EPIPE;
+	}
+
+	urb->actual_length = len;
+	urb->status = stat;
+	if (urb->complete)
+		urb->complete(urb);
+
+	return USB_ST_NOERROR;
+}
+/*-------------------------------------------------------------------------*/
+
+static int rh_unlink_urb(urb_t *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	uhci->rh.send = 0;
+	del_timer(&uhci->rh.rh_int_timer);
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+
+/*
+ * This is just incredibly fragile. The timings must be just
+ * right, and they aren't really documented very well.
+ *
+ * Note the short delay between disabling reset and enabling
+ * the port..
+ */
+static void uhci_reset_port(unsigned int port)
+{
+	unsigned short status;
+
+	status = inw(port);
+	outw(status | USBPORTSC_PR, port);		/* reset port */
+	wait_ms(10);
+	outw(status & ~USBPORTSC_PR, port);
+	udelay(50);
+
+	status = inw(port);
+	outw(status | USBPORTSC_PE, port);		/* enable port */
+	wait_ms(10);
+
+	status = inw(port);
+	if (!(status & USBPORTSC_PE)) {
+		outw(status | USBPORTSC_PE, port);	/* one more try at enabling port */
+		wait_ms(50);
+	}
+
+}
+
+void uhci_free_pending(struct uhci *uhci)
+{
+	struct list_head *tmp, *head;
+
+	/* Free all of the pending QH's and TD's */
+	head = &uhci->td_free_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+                list_del(&td->list);
+                INIT_LIST_HEAD(&td->list);
+
+		uhci_td_free(td);
+	}
+
+	head = &uhci->qh_free_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, list);
+
+		tmp = tmp->next;
+
+                list_del(&qh->list);
+                INIT_LIST_HEAD(&qh->list);
+
+		uhci_qh_free(qh);
+	}
+}
+
+static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
+{
+	struct uhci *uhci = __uhci;
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short status;
+	unsigned long flags;
+	struct list_head *tmp, *head;
+	urb_t *urb;
+
+	/*
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause
+	 */
+	status = inw(io_addr + USBSTS);
+	if (!status)	/* shared interrupt, not mine */
+		return;
+	outw(status, io_addr + USBSTS);
+
+	if (status & ~(USBSTS_USBINT | USBSTS_ERROR)) {
+		if (status & USBSTS_RD)
+			printk(KERN_INFO "uhci: resume detected, not implemented\n");
+		if (status & USBSTS_HSE)
+			printk(KERN_ERR "uhci: host system error, PCI problems?\n");
+		if (status & USBSTS_HCPE)
+			printk(KERN_ERR "uhci: host controller process error. something bad happened\n");
+		if (status & USBSTS_HCH) {
+			printk(KERN_ERR "uhci: host controller halted. very bad\n");
+			/* FIXME: Reset the controller, fix the offending TD */
+		}
+	}
+
+	/* Free all of the pending QH's and TD's */
+	spin_lock(&uhci->freelist_lock);
+	uhci_free_pending(uhci);
+	spin_unlock(&uhci->freelist_lock);
+
+	/* Walk the list of pending TD's to see which ones completed.. */
+	nested_lock(&uhci->irqlist_lock, flags);
+	head = &uhci->interrupt_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
+
+		urb = td->urb;
+
+		tmp = tmp->next;
+
+		/* Checks the status and does all of the magic necessary */
+		uhci_transfer_result(urb);
+	}
+	nested_unlock(&uhci->irqlist_lock, flags);
+}
+
+static void reset_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+
+	/* Global reset for 50ms */
+	outw(USBCMD_GRESET, io_addr + USBCMD);
+	wait_ms(50);
+	outw(0, io_addr + USBCMD);
+	wait_ms(10);
+}
+
+static void start_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	int timeout = 1000;
+
+	/*
+	 * Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw(USBCMD_HCRESET, io_addr + USBCMD);
+	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
+		if (!--timeout) {
+			printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");
+			break;
+		}
+	}
+
+	/* Turn on all interrupts */
+	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+		io_addr + USBINTR);
+
+	/* Start at frame 0 */
+	outw(0, io_addr + USBFRNUM);
+	outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+}
+
+/*
+ * Allocate a frame list, and then setup the skeleton
+ *
+ * The hardware doesn't really know any difference
+ * in the queues, but the order does matter for the
+ * protocols higher up. The order is:
+ *
+ *  - any isochronous events handled before any
+ *    of the queues. We don't do that here, because
+ *    we'll create the actual TD entries on demand.
+ *  - The first queue is the "interrupt queue".
+ *  - The second queue is the "control queue".
+ *  - The third queue is "bulk data".
+ */
+static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
+{
+	int i, port;
+	struct uhci *uhci;
+	struct usb_bus *bus;
+
+	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
+	if (!uhci)
+		return NULL;
+
+	memset(uhci, 0, sizeof(*uhci));
+
+	uhci->irq = -1;
+	uhci->io_addr = io_addr;
+	uhci->io_size = io_size;
+
+	INIT_LIST_HEAD(&uhci->interrupt_list);
+	INIT_LIST_HEAD(&uhci->urb_list);
+	INIT_LIST_HEAD(&uhci->td_free_list);
+	INIT_LIST_HEAD(&uhci->qh_free_list);
+
+	spin_lock_init(&uhci->urblist_lock);
+	spin_lock_init(&uhci->framelist_lock);
+	spin_lock_init(&uhci->freelist_lock);
+	nested_init(&uhci->irqlist_lock);
+
+	/* We need exactly one page (per UHCI specs), how convenient */
+	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
+	uhci->fl = (void *)__get_free_page(GFP_KERNEL);
+	if (!uhci->fl)
+		goto au_free_uhci;
+
+	bus = usb_alloc_bus(&uhci_device_operations);
+	if (!bus)
+		goto au_free_fl;
+
+	uhci->bus = bus;
+	bus->hcpriv = uhci;
+
+	/* Initialize the root hub */
+
+	/* UHCI specs says devices must have 2 ports, but goes on to say */
+	/*  they may have more but give no way to determine how many they */
+	/*  have. However, according to the UHCI spec, Bit 7 is always set */
+	/*  to 1. So we try to use this to our advantage */
+	for (port = 0; port < (io_size - 0x10) / 2; port++) {
+		unsigned int portstatus;
+
+		portstatus = inw(io_addr + 0x10 + (port * 2));
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	if (debug)
+		info("detected %d ports", port);
+
+	/* This is experimental so anything less than 2 or greater than 8 is */
+	/*  something weird and we'll ignore it */
+	if (port < 2 || port > 8) {
+		info("port count misdetected? forcing to 2 ports");
+		port = 2;
+	}
+
+	uhci->rh.numports = port;
+
+	/*
+	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
+	 * then link int1 to control and control to bulk
+	 */
+	for (i = 1; i < 9; i++) {
+		struct uhci_td *td = &uhci->skeltd[i];
+
+		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+		td->link = virt_to_bus(&uhci->skeltd[i - 1]);
+	}
+
+
+	uhci_fill_td(&uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH;
+
+	uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH;
+	uhci->skel_control_qh.element = UHCI_PTR_TERM;
+
+	uhci->skel_bulk_qh.link = UHCI_PTR_TERM;
+	uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
+
+	/*
+	 * Fill the frame list: make all entries point to
+	 * the proper interrupt queue.
+	 *
+	 * This is probably silly, but it's a simple way to
+	 * scatter the interrupt queues in a way that gives
+	 * us a reasonable dynamic range for irq latencies.
+	 */
+	for (i = 0; i < 1024; i++) {
+		struct uhci_td *irq = &uhci->skel_int2_td;
+
+		if (i & 1) {
+			irq++;
+			if (i & 2) {
+				irq++;
+				if (i & 4) { 
+					irq++;
+					if (i & 8) { 
+						irq++;
+						if (i & 16) {
+							irq++;
+							if (i & 32) {
+								irq++;
+								if (i & 64)
+									irq++;
+							}
+						}
+					}
+				}
+			}
+		}
+
+		/* Only place we don't use the frame list routines */
+		uhci->fl->frame[i] =  virt_to_bus(irq);
+	}
+
+	return uhci;
+
+/*
+ * error exits:
+ */
+au_free_fl:
+	free_page((unsigned long)uhci->fl);
+au_free_uhci:
+	kfree(uhci);
+
+	return NULL;
+}
+
+/*
+ * De-allocate all resources..
+ */
+static void release_uhci(struct uhci *uhci)
+{
+	if (uhci->irq >= 0) {
+		free_irq(uhci->irq, uhci);
+		uhci->irq = -1;
+	}
+
+	if (uhci->fl) {
+		free_page((unsigned long)uhci->fl);
+		uhci->fl = NULL;
+	}
+
+	usb_free_bus(uhci->bus);
+	kfree(uhci);
+}
+
+int uhci_start_root_hub(struct uhci *uhci)
+{
+	struct usb_device *usb_dev;
+
+	usb_dev = usb_alloc_dev(NULL, uhci->bus);
+	if (!usb_dev)
+		return -1;
+
+	usb_to_uhci(usb_dev)->uhci = uhci;
+
+	uhci->bus->root_hub = usb_dev;
+	usb_connect(usb_dev);
+
+	if (usb_new_device(usb_dev) != 0) {
+		usb_free_dev(usb_dev);
+
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * If we've successfully found a UHCI, now is the time to increment the
+ * module usage count, and return success..
+ */
+static int setup_uhci(int irq, unsigned int io_addr, unsigned int io_size)
+{
+	int retval;
+	struct uhci *uhci;
+
+	uhci = alloc_uhci(io_addr, io_size);
+	if (!uhci)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&uhci->uhci_list);
+	list_add(&uhci->uhci_list, &uhci_list);
+
+	request_region(uhci->io_addr, io_size, "usb-uhci");
+
+	reset_hc(uhci);
+
+	usb_register_bus(uhci->bus);
+	start_hc(uhci);
+
+	retval = -EBUSY;
+	if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) {
+		uhci->irq = irq;
+
+		if (!uhci_start_root_hub(uhci))
+			return 0;
+	}
+
+	/* Couldn't allocate IRQ if we got here */
+	list_del(&uhci->uhci_list);
+	INIT_LIST_HEAD(&uhci->uhci_list);
+
+	reset_hc(uhci);
+	release_region(uhci->io_addr, uhci->io_size);
+	release_uhci(uhci);
+
+	return retval;
+}
+
+static int found_uhci(struct pci_dev *dev)
+{
+	int i;
+
+	/* Search for the IO base address.. */
+	for (i = 0; i < 6; i++) {
+		unsigned int io_addr = dev->resource[i].start;
+		unsigned int io_size =
+			dev->resource[i].end - dev->resource[i].start + 1;
+
+		/* IO address? */
+		if (!(dev->resource[i].flags & 1))
+			continue;
+
+		/* Is it already in use? */
+		if (check_region(io_addr, io_size))
+			break;
+
+		/* disable legacy emulation */
+		pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+		pci_enable_device(dev);
+
+		if (!dev->irq) {
+			err("found UHCI device with no IRQ assigned. check BIOS settings!");
+			continue;
+		}
+
+		return setup_uhci(dev->irq, io_addr, io_size);
+	}
+
+	return -1;
+}
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+	static int down = 0;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (down) {
+			dbg("received extra suspend event");
+			break;
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (!down) {
+			dbg("received bogus resume event");
+			break;
+		}
+		down = 0;
+		break;
+	}
+	return 0;
+}
+#endif
+
+int uhci_init(void)
+{
+	int retval;
+	struct pci_dev *dev;
+	u8 type;
+
+	retval = -ENOMEM;
+
+	/* We throw all of the TD's and QH's into a kmem cache */
+	/* TD's and QH's need to be 16 byte aligned and SLAB_HWCACHE_ALIGN */
+	/*  does this for us */
+	uhci_td_cachep = kmem_cache_create("uhci_td",
+		sizeof(struct uhci_td), 0,
+		SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	if (!uhci_td_cachep)
+		goto td_failed;
+
+	uhci_qh_cachep = kmem_cache_create("uhci_qh",
+		sizeof(struct uhci_qh), 0,
+		SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	if (!uhci_qh_cachep)
+		goto qh_failed;
+
+	retval = -ENODEV;
+	dev = NULL;
+	for (;;) {
+		dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
+		if (!dev)
+			break;
+
+		/* Is it the UHCI programming interface? */
+		pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
+		if (type != 0)
+			continue;
+
+		/* Ok set it up */
+		retval = found_uhci(dev);
+	}
+
+	/* We only want to return an error code if ther was an error */
+	/*  and we didn't find a UHCI controller */
+	if (retval && uhci_list.next == &uhci_list)
+		goto init_failed;
+
+#ifdef CONFIG_APM
+	apm_register_callback(&handle_apm_event);
+#endif
+
+	return 0;
+
+init_failed:
+	if (kmem_cache_destroy(uhci_qh_cachep))
+		printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+qh_failed:
+	if (kmem_cache_destroy(uhci_td_cachep))
+		printk(KERN_INFO "uhci: not all TD's were freed\n");
+
+td_failed:
+	return retval;
+}
+
+void uhci_cleanup(void)
+{
+	struct list_head *next, *tmp, *head = &uhci_list;
+	int i;
+	unsigned long flags;
+
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
+
+		next = tmp->next;
+
+		list_del(&uhci->uhci_list);
+		INIT_LIST_HEAD(&uhci->uhci_list);
+
+		if (uhci->bus->root_hub)
+			usb_disconnect(&uhci->bus->root_hub);
+
+		usb_deregister_bus(uhci->bus);
+
+		reset_hc(uhci);
+		release_region(uhci->io_addr, uhci->io_size);
+
+		/* Free any outstanding TD's and QH's */
+		spin_lock_irqsave(&uhci->freelist_lock, flags);
+		uhci_free_pending(uhci);
+		spin_unlock_irqrestore(&uhci->freelist_lock, flags);
+
+		release_uhci(uhci);
+
+		tmp = next;
+	}
+
+	if (kmem_cache_destroy(uhci_qh_cachep))
+		printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+	if (kmem_cache_destroy(uhci_td_cachep))
+		printk(KERN_INFO "uhci: not all TD's were freed\n");
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return uhci_init();
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+	apm_unregister_callback(&handle_apm_event);
+#endif
+	uhci_cleanup();
+}
+#endif //MODULE
+
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.41/linux/drivers/usb/uhci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/uhci.h	Mon Jan 31 16:42:02 2000
@@ -0,0 +1,425 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+#include <linux/list.h>
+
+#include "usb.h"
+
+/*
+ * This nested spinlock code is courtesy of Davide Libenzi <dlibenzi@maticad.it>
+ */
+struct s_nested_lock {
+	spinlock_t lock;
+	void *uniq;
+	short int count;
+};
+
+#define nested_init(snl) \
+	spin_lock_init(&(snl)->lock); \
+	(snl)->uniq = NULL; \
+	(snl)->count = 0;
+
+#define nested_lock(snl, flags) \
+	if ((snl)->uniq == current) { \
+		(snl)->count++; \
+		flags = 0; /* No warnings */ \
+	} else { \
+		spin_lock_irqsave(&(snl)->lock, flags); \
+		(snl)->count++; \
+		(snl)->uniq = current; \
+	}
+
+#define nested_unlock(snl, flags) \
+	if (!--(snl)->count) { \
+		(snl)->uniq = NULL; \
+		spin_unlock_irqrestore(&(snl)->lock, flags); \
+	}
+
+/*
+ * Universal Host Controller Interface data structures and defines
+ */
+
+/* Command register */
+#define USBCMD		0
+#define   USBCMD_RS		0x0001	/* Run/Stop */
+#define   USBCMD_HCRESET	0x0002	/* Host reset */
+#define   USBCMD_GRESET		0x0004	/* Global reset */
+#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
+#define   USBCMD_FGR		0x0010	/* Force Global Resume */
+#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
+#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
+#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS		2
+#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
+#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
+#define   USBSTS_RD		0x0004	/* Resume Detect */
+#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH		0x0020	/* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR		4
+#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
+#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
+#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
+#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
+
+#define USBFRNUM	6
+#define USBFLBASEADD	8
+#define USBSOF		12
+
+/* USB port status and control registers */
+#define USBPORTSC1	16
+#define USBPORTSC2	18
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
+#define   USBPORTSC_PE		0x0004	/* Port Enable */
+#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
+#define   USBPORTSC_LS		0x0030	/* Line Status */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT	0x2000	/* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE	0x7FF	/* for UHCI controller TD */
+
+#define UHCI_PTR_BITS		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
+#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
+
+struct uhci_td;
+
+struct uhci_qh {
+	/* Hardware fields */
+	__u32 link;				/* Next queue */
+	__u32 element;				/* Queue element pointer */
+
+	/* Software fields */
+	struct uhci_qh *prevqh, *nextqh;	/* Previous and next TD in queue */
+
+	struct uhci_device *dev;		/* The owning device */
+
+	struct list_head list;
+} __attribute__((aligned(16)));
+
+struct uhci_framelist {
+	__u32 frame[UHCI_NUMFRAMES];
+} __attribute__((aligned(4096)));
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
+#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
+#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
+#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
+#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
+#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
+#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
+#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
+#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK	0x7FF		/* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE		19
+#define TD_PID			0xFF
+
+#define uhci_maxlen(token)	((token) >> 21)
+#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
+#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
+#define uhci_packetid(token)	((token) & 0xff)
+#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
+
+/*
+ * The documentation says "4 words for hardware, 4 words for software".
+ *
+ * That's silly, the hardware doesn't care. The hardware only cares that
+ * the hardware words are 16-byte aligned, and we can have any amount of
+ * sw space after the TD entry as far as I can tell.
+ *
+ * But let's just go with the documentation, at least for 32-bit machines.
+ * On 64-bit machines we probably want to take advantage of the fact that
+ * hw doesn't really care about the size of the sw-only area.
+ *
+ * Alas, not anymore, we have more than 4 words for software, woops
+ */
+struct uhci_td {
+	/* Hardware fields */
+	__u32 link;
+	__u32 status;
+	__u32 info;
+	__u32 buffer;
+
+	/* Software fields */
+	unsigned int *frameptr;		/* Frame list pointer */
+	struct uhci_td *prevtd, *nexttd; /* Previous and next TD in queue */
+
+	struct uhci_device *dev;
+	struct urb *urb;		/* URB this TD belongs to */
+	struct uhci_td *next;		/* List of chained TD's for an URB */
+
+	struct list_head irq_list;	/* Active interrupt list.. */
+	struct list_head list;
+} __attribute__((aligned(16)));
+
+/*
+ * Note the alignment requirements of the entries
+ *
+ * Each UHCI device has pre-allocated QH and TD entries.
+ * You can use more than the pre-allocated ones, but I
+ * don't see you usually needing to.
+ */
+struct uhci;
+
+struct uhci_device {
+	struct usb_device	*usb;
+
+	atomic_t		refcnt;
+
+	struct uhci		*uhci;		/* HC this device is connected to */
+};
+
+#define uhci_to_usb(uhci)	((uhci)->usb)
+#define usb_to_uhci(usb)	((struct uhci_device *)(usb)->hcpriv)
+
+/*
+ * There are various standard queues. We set up several different
+ * queues for each of the three basic queue types: interrupt,
+ * control, and bulk.
+ *
+ *  - There are various different interrupt latencies: ranging from
+ *    every other USB frame (2 ms apart) to every 256 USB frames (ie
+ *    256 ms apart). Make your choice according to how obnoxious you
+ *    want to be on the wire, vs how critical latency is for you.
+ *  - The control list is done every frame.
+ *  - There are 4 bulk lists, so that up to four devices can have a
+ *    bulk list of their own and when run concurrently all four lists
+ *    will be be serviced.
+ *
+ * This is a bit misleading, there are various interrupt latencies, but they
+ * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
+ * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
+ * problem
+ *
+ * In the case of the root hub, these QH's are just head's of qh's. Don't
+ * be scared, it kinda makes sense. Look at this wonderful picture care of
+ * Linus:
+ *
+ *  generic-  ->  dev1-  ->  generic-  ->  dev1-  ->  control-  ->  bulk- -> ...
+ *   iso-QH      iso-QH       irq-QH      irq-QH        QH           QH
+ *      |           |            |           |           |            |
+ *     End     dev1-iso-TD1     End     dev1-irq-TD1    ...          ... 
+ *                  |
+ *             dev1-iso-TD2
+ *                  |
+ *                ....
+ *
+ * This may vary a bit (the UHCI docs don't explicitly say you can put iso
+ * transfers in QH's and all of their pictures don't have that either) but
+ * other than that, that is what we're doing now
+ *
+ * And now we don't put Iso transfers in QH's, so we don't waste one on it
+ * --jerdfelt
+ *
+ * To keep with Linus' nomenclature, this is called the QH skeleton. These
+ * labels (below) are only signficant to the root hub's QH's
+ */
+
+#define UHCI_NUM_SKELTD		9
+#define skel_int1_td		skeltd[0]
+#define skel_int2_td		skeltd[1]
+#define skel_int4_td		skeltd[2]
+#define skel_int8_td		skeltd[3]
+#define skel_int16_td		skeltd[4]
+#define skel_int32_td		skeltd[5]
+#define skel_int64_td		skeltd[6]
+#define skel_int128_td		skeltd[7]
+#define skel_int256_td		skeltd[8]
+
+#define UHCI_NUM_SKELQH		2
+#define skel_control_qh		skelqh[0]
+#define skel_bulk_qh		skelqh[1]
+
+/*
+ * Search tree for determining where <interval> fits in the
+ * skelqh[] skeleton.
+ *
+ * An interrupt request should be placed into the slowest skelqh[]
+ * which meets the interval/period/frequency requirement.
+ * An interrupt request is allowed to be faster than <interval> but not slower.
+ *
+ * For a given <interval>, this function returns the appropriate/matching
+ * skelqh[] index value.
+ *
+ * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
+ * is 255 ms.  However, we do need an int1_qh since 1 is a valid interval
+ * and we should meet that frequency when requested to do so.
+ * This will require some change(s) to the UHCI skeleton.
+ */
+static inline int __interval_to_skel(int interval)
+{
+	if (interval < 16) {
+		if (interval < 4) {
+			if (interval < 2)
+				return 0;	/* int1 for 0-1 ms */
+			return 1;		/* int2 for 2-3 ms */
+		}
+		if (interval < 8)
+			return 2;		/* int4 for 4-7 ms */
+		return 3;			/* int8 for 8-15 ms */
+	}
+	if (interval < 64) {
+		if (interval < 32)
+			return 4;		/* int16 for 16-31 ms */
+		return 5;			/* int32 for 32-63 ms */
+	}
+	if (interval < 128)
+		return 6;			/* int64 for 64-127 ms */
+	return 7;				/* int128 for 128-255 ms (Max.) */
+}
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	int c_p_r[8];
+	struct timer_list rh_int_timer;
+};
+
+/*
+ * This describes the full uhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct uhci {
+	int irq;
+	unsigned int io_addr;
+	unsigned int io_size;
+
+	struct list_head uhci_list;
+
+	struct usb_bus *bus;
+
+	struct uhci_td skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
+	struct uhci_qh skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
+
+	struct uhci_framelist *fl;		/* Frame list */
+
+	struct s_nested_lock irqlist_lock;
+	struct list_head interrupt_list;	/* List of interrupt-active TD's for this uhci */
+
+	spinlock_t urblist_lock;
+	struct list_head urb_list;
+
+	spinlock_t framelist_lock;
+
+	spinlock_t freelist_lock;
+	struct list_head td_free_list;
+	struct list_head qh_free_list;
+
+	struct virt_root_hub rh;	/* private data of the virtual root hub */
+};
+
+struct urb_priv {
+	struct uhci_qh *qh;		/* QH for this URB */
+	struct uhci_td *begin;
+	struct uhci_td *end;
+};
+
+/* -------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_INTERFACE		0x01
+#define RH_ENDPOINT		0x02
+#define RH_OTHER		0x03
+
+#define RH_CLASS		0x20
+#define RH_VENDOR		0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	0x00
+#define RH_PORT_ENABLE		0x01
+#define RH_PORT_SUSPEND		0x02
+#define RH_PORT_OVER_CURRENT	0x03
+#define RH_PORT_RESET		0x04
+#define RH_PORT_POWER		0x08
+#define RH_PORT_LOW_SPEED	0x09
+#define RH_C_PORT_CONNECTION	0x10
+#define RH_C_PORT_ENABLE	0x11
+#define RH_C_PORT_SUSPEND	0x12
+#define RH_C_PORT_OVER_CURRENT	0x13
+#define RH_C_PORT_RESET		0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	0x00
+#define RH_C_HUB_OVER_CURRENT	0x01
+#define RH_DEVICE_REMOTE_WAKEUP	0x00
+#define RH_ENDPOINT_STALL	0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP		0x00
+
+#define RH_ACK			0x01
+#define RH_REQ_ERR		-1
+#define RH_NACK			0x00
+
+/* needed for the debugging code */
+struct uhci_td *uhci_link_to_td(unsigned int element);
+
+/* Debugging code */
+void uhci_show_td(struct uhci_td *td);
+void uhci_show_status(struct uhci *uhci);
+void uhci_show_queue(struct uhci_qh *qh);
+void uhci_show_queues(struct uhci *uhci);
+
+#endif
+
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.41/linux/drivers/usb/usb-core.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/usb-core.c	Mon Jan 31 10:10:07 2000
@@ -132,6 +132,9 @@
 #ifdef CONFIG_USB_UHCI
 	uhci_init();
 #endif
+#ifdef CONFIG_USB_UHCI_ALT
+	uhci_init();
+#endif
 #ifdef CONFIG_USB_OHCI
 	ohci_hcd_init(); 
 #endif
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/usb-serial.c linux/drivers/usb/usb-serial.c
--- v2.3.41/linux/drivers/usb/usb-serial.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/usb-serial.c	Mon Jan 31 10:09:56 2000
@@ -996,7 +996,7 @@
 //	dbg("whiteheat_writememory %x, %d", address, length);
 
 	if (!transfer_buffer) {
-		err("whiteheat_writememory: kmalloc(%d) failed.\n", length);
+		err("whiteheat_writememory: kmalloc(%d) failed.", length);
 		return -ENOMEM;
 	}
 	memcpy (transfer_buffer, data, length);
@@ -1078,7 +1078,7 @@
 		response = whiteheat_writememory (serial, record->address, 
 				(unsigned char *)record->data, record->data_size, 0xa0);
 		if (response < 0) {
-			err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)\n", 
+			err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)", 
 				response, record->address, record->data, record->data_size);
 			break;
 		}
@@ -1127,7 +1127,7 @@
 	dbg("visor_serial_close port %d", port);
 			 
 	if (!transfer_buffer) {
-		err("visor_serial_close: kmalloc(%d) failed.\n", 0x12);
+		err("visor_serial_close: kmalloc(%d) failed.", 0x12);
 	} else {
 		/* send a shutdown message to the device */
 		usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
@@ -1175,7 +1175,7 @@
 	unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
 
 	if (!transfer_buffer) {
-		err("visor_startup: kmalloc(%d) failed.\n", 256);
+		err("visor_startup: kmalloc(%d) failed.", 256);
 		return -ENOMEM;
 	}
 
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/usb-uhci-debug.h linux/drivers/usb/usb-uhci-debug.h
--- v2.3.41/linux/drivers/usb/usb-uhci-debug.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usb-uhci-debug.h	Mon Jan 31 10:10:07 2000
@@ -0,0 +1,195 @@
+#ifdef DEBUG
+
+static void uhci_show_qh (puhci_desc_t qh)
+{
+	if (qh->type != QH_TYPE) {
+		dbg("qh has not QH_TYPE");
+		return;
+	}
+	dbg("uhci_show_qh %p (%08lX):", qh, virt_to_bus (qh));
+
+	if (qh->hw.qh.head & UHCI_PTR_TERM)
+		dbg("Head Terminate");
+	else {
+		if (qh->hw.qh.head & UHCI_PTR_QH)
+			dbg("Head points to QH");
+		else
+			dbg("Head points to TD");
+
+		dbg("head: %08X", qh->hw.qh.head & ~UHCI_PTR_BITS);
+	}
+	if (qh->hw.qh.element & UHCI_PTR_TERM)
+		dbg("Element Terminate");
+	else {
+
+		if (qh->hw.qh.element & UHCI_PTR_QH)
+			dbg("Element points to QH");
+		else
+			dbg("Element points to TD");
+		dbg("element: %08X", qh->hw.qh.element & ~UHCI_PTR_BITS);
+	}
+}
+#endif
+
+static void uhci_show_td (puhci_desc_t td)
+{
+	char *spid;
+	warn("uhci_show_td %p (%08lX) ", td, virt_to_bus (td));
+
+	switch (td->hw.td.info & 0xff) {
+	case USB_PID_SETUP:
+		spid = "SETUP";
+		break;
+	case USB_PID_OUT:
+		spid = " OUT ";
+		break;
+	case USB_PID_IN:
+		spid = " IN  ";
+		break;
+	default:
+		spid = "  ?  ";
+		break;
+	}
+
+	warn("MaxLen=%02x DT%d EndPt=%x Dev=%x, PID=%x(%s) (buf=%08x)",
+	     td->hw.td.info >> 21,
+	     ((td->hw.td.info >> 19) & 1),
+	     (td->hw.td.info >> 15) & 15,
+	     (td->hw.td.info >> 8) & 127,
+	     (td->hw.td.info & 0xff),
+	     spid,
+	     td->hw.td.buffer);
+
+	warn("Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
+	     td->hw.td.status & 0x7ff,
+	     ((td->hw.td.status >> 27) & 3),
+	     (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
+	     (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
+	     (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
+	     (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
+	     (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
+	     (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+	     (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
+	     (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
+	     (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+	     (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
+		);
+#if 1
+	if (td->hw.td.link & UHCI_PTR_TERM)
+		warn("Link Terminate");
+	else {
+		if (td->hw.td.link & UHCI_PTR_QH)
+			warn("%s, link points to QH @ %08x",
+			     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
+			     td->hw.td.link & ~UHCI_PTR_BITS);
+		else
+			warn("%s, link points to TD @ %08x",
+			     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : " Breadth first"),
+			     td->hw.td.link & ~UHCI_PTR_BITS);
+	}
+#endif
+}
+#ifdef DEBUG
+static void uhci_show_td_queue (puhci_desc_t td)
+{
+	dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td));
+	while (1) {
+		uhci_show_td (td);
+		if (td->hw.td.link & UHCI_PTR_TERM)
+			break;
+		//if(!(td->hw.td.link&UHCI_PTR_DEPTH))
+		//      break;
+		if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
+			td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
+		else {
+			dbg("td points to itself!");
+			break;
+		}
+//              schedule();
+	}
+}
+
+static void uhci_show_queue (puhci_desc_t qh)
+{
+	dbg("uhci_show_queue %p:", qh);
+	while (1) {
+		uhci_show_qh (qh);
+
+		if (qh->hw.qh.element & UHCI_PTR_QH)
+			dbg("Warning: qh->element points to qh!");
+		else if (!(qh->hw.qh.element & UHCI_PTR_TERM))
+			uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+
+		if (qh->hw.qh.head & UHCI_PTR_TERM)
+			break;
+
+		if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
+			qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
+		else {
+			dbg("qh points to itself!");
+			break;
+		}
+	}
+}
+
+static void uhci_show_sc (int port, unsigned short status)
+{
+	dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
+	     port,
+	     status,
+	     (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+	     (status & USBPORTSC_PR) ? "PortReset " : "",
+	     (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+	     (status & USBPORTSC_RD) ? "ResumeDetect " : "",
+	     (status & USBPORTSC_PEC) ? "EnableChange " : "",
+	     (status & USBPORTSC_PE) ? "PortEnabled " : "",
+	     (status & USBPORTSC_CSC) ? "ConnectChange " : "",
+	     (status & USBPORTSC_CCS) ? "PortConnected " : "");
+}
+
+void uhci_show_status (puhci_t s)
+{
+	unsigned int io_addr = s->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	usbcmd = inw (io_addr + 0);
+	usbstat = inw (io_addr + 2);
+	usbint = inw (io_addr + 4);
+	usbfrnum = inw (io_addr + 6);
+	flbaseadd = inl (io_addr + 8);
+	sof = inb (io_addr + 12);
+	portsc1 = inw (io_addr + 16);
+	portsc2 = inw (io_addr + 18);
+
+	dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
+	     usbcmd,
+	     (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
+	     (usbcmd & USBCMD_CF) ? "CF " : "",
+	     (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
+	     (usbcmd & USBCMD_FGR) ? "FGR " : "",
+	     (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
+	     (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
+	     (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+	     (usbcmd & USBCMD_RS) ? "RS " : "");
+
+	dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
+	     usbstat,
+	     (usbstat & USBSTS_HCH) ? "HCHalted " : "",
+	     (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
+	     (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
+	     (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
+	     (usbstat & USBSTS_ERROR) ? "USBError " : "",
+	     (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+	dbg("  usbint    =     %04x", usbint);
+	dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
+	     0xfff & (4 * (unsigned int) usbfrnum));
+	dbg("  flbaseadd = %08x", flbaseadd);
+	dbg("  sof       =       %02x", sof);
+	uhci_show_sc (1, portsc1);
+	uhci_show_sc (2, portsc2);
+}
+#endif
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.3.41/linux/drivers/usb/usb-uhci.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/usb-uhci.c	Mon Jan 31 10:10:07 2000
@@ -43,7 +43,7 @@
 
 #include "usb.h"
 #include "usb-uhci.h"
-#include "uhci-debug.h"
+#include "usb-uhci-debug.h"
 
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.41/linux/drivers/usb/usb.c	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/usb.c	Mon Jan 31 10:10:02 2000
@@ -1595,17 +1595,34 @@
 	tbuf = kmalloc(256, GFP_KERNEL);
 	if (!tbuf)
 		return -ENOMEM;
+
+	/* get langid for strings if it's not yet known */
+	if (!dev->have_langid) {
+		err = usb_get_string(dev, 0, 0, tbuf, 4);
+		if (err < 0) {
+			err("error getting string descriptor 0 (error=%d)", err);
+			goto errout;
+		} else if (tbuf[0] < 4) {
+			err("string descriptor 0 too short");
+			err = -EINVAL;
+			goto errout;
+		} else {
+			dev->have_langid = -1;
+			dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+				/* always use the first langid listed */
+			info("USB device number %d default language ID 0x%x",
+				dev->devnum, dev->string_langid);
+		}
+	}
+
 	/*
-	 * is this two step process necessary? can't we just
-	 * ask for a maximum length string and then take the length
-	 * that was returned?
+	 * Just ask for a maximum length string and then take the length
+	 * that was returned.
 	 */
-	err = usb_get_string(dev, dev->string_langid, index, tbuf, 4);
-	if (err < 0)
-		goto errout;
-	err = usb_get_string(dev, dev->string_langid, index, tbuf, tbuf[0]);
+	err = usb_get_string(dev, dev->string_langid, index, tbuf, 255);
 	if (err < 0)
 		goto errout;
+	info("actual string desc. length = %d", err);
 
 	size--;		/* leave room for trailing NULL char in output buffer */
 	for (idx = 0, u = 2; u < err; u += 2) {
@@ -1633,7 +1650,6 @@
  */
 int usb_new_device(struct usb_device *dev)
 {
-	unsigned char *buf;
 	int addr, err;
 	int tmp;
 
@@ -1708,21 +1724,6 @@
 	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
 		err("failed to set default configuration");
 		return -1;
-	}
-	/* get langid for strings */
-	buf = kmalloc(256, GFP_KERNEL);
-	if (!buf) {
-		err("out of memory\n");
-	} else {
-		err = usb_get_string(dev, 0, 0, buf, 4);
-		if (err < 0) {
-			err("error getting string descriptor 0 (error=%d)\n", err);
-		} else if (buf[0] < 4) {
-			err("string descriptpr 0 too short\n");
-		} else
-			dev->string_langid = buf[2] | (buf[3]<< 8);
-		kfree(buf);
-		info("USB device number %d default language ID 0x%x", dev->devnum, dev->string_langid);
 	}
 
 	if (dev->descriptor.iManufacturer)
diff -u --recursive --new-file v2.3.41/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.41/linux/drivers/usb/usb.h	Fri Jan 28 15:09:08 2000
+++ linux/drivers/usb/usb.h	Mon Jan 31 10:10:07 2000
@@ -509,6 +509,7 @@
 	struct usb_device_descriptor descriptor;/* Descriptor */
 	struct usb_config_descriptor *config;	/* All of the configs */
 
+	int have_langid;		/* whether string_langid is valid yet */
 	int string_langid;		/* language ID for strings */
   
 	void *hcpriv;			/* Host Controller private data */
diff -u --recursive --new-file v2.3.41/linux/drivers/video/dn_accel.h linux/drivers/video/dn_accel.h
--- v2.3.41/linux/drivers/video/dn_accel.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/dn_accel.h	Mon Jan 31 10:30:00 2000
@@ -0,0 +1,9 @@
+#ifndef _DN_ACCEL_H_
+#define _DN_ACCEL_H_
+
+#include <linux/fb.h>
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+	       int x_count, int y_count);
+
+#endif
diff -u --recursive --new-file v2.3.41/linux/drivers/video/dn_cfb4.c linux/drivers/video/dn_cfb4.c
--- v2.3.41/linux/drivers/video/dn_cfb4.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/dn_cfb4.c	Mon Jan 31 23:43:51 2000
@@ -0,0 +1,546 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/apollohw.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <video/fbcon.h>
+#include <video/fbcon-mfb.h>
+#include "dn_accel.h"
+
+/* apollo video HW definitions */
+
+/*
+ * Control Registers.   IOBASE + $x
+ *
+ * Note: these are the Memory/IO BASE definitions for a mono card set to the
+ * alternate address
+ *
+ * Control 3A and 3B serve identical functions except that 3A
+ * deals with control 1 and 3b deals with Color LUT reg.
+ */
+
+#define AP_IOBASE       0x3d0          /* Base address of 1 plane board. */
+#define AP_STATUS       isaIO2mem(AP_IOBASE+0) /* Status register.  Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
+#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
+#define AP_ROP_1        isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8) /* Control Register 0.  Read/Write */
+#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa) /* Control Register 1.  Read/Write */
+#define AP_CONTROL_2    isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
+#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
+#define AP_LUT_RED     isaIO2mem(AP_IOBASE+9) /* Red Lookup Table register. Write */
+#define AP_LUT_GREEN  isaIO2mem(AP_IOBASE+0xb) /* Green Lookup Table register. Write */
+#define AP_LUT_BLUE   isaIO2mem(AP_IOBASE+0xd) /* Blue Lookup Table register. Write */
+#define AP_AD_CHANNEL   isaIO2mem(AP_IOBASE+0xf) /* A/D Result/Channel register. Read/Write */
+
+
+#define FRAME_BUFFER_START 0x0A0000
+#define FRAME_BUFFER_LEN 0x20000
+
+/* CREG 0 */
+#define VECTOR_MODE 0x40 /* 010x.xxxx */
+#define DBLT_MODE   0x80 /* 100x.xxxx */
+#define NORMAL_MODE 0xE0 /* 111x.xxxx */
+#define SHIFT_BITS  0x1F /* xxx1.1111 */
+        /* other bits are Shift value */
+
+/* CREG 1 */
+#define AD_BLT      0x80 /* 1xxx.xxxx */
+
+#define ROP_EN          0x10 /* xxx1.xxxx */
+#define DST_EQ_SRC      0x00 /* xxx0.xxxx */
+#define nRESET_SYNC     0x08 /* xxxx.1xxx */
+#define SYNC_ENAB       0x02 /* xxxx.xx1x */
+
+#define BLANK_DISP      0x00 /* xxxx.xxx0 */
+#define ENAB_DISP       0x01 /* xxxx.xxx1 */
+
+#define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
+
+/* CREG 2B */
+
+/*
+ * Following 3 defines are common to 1, 4 and 8 plane.
+ */
+
+#define S_DATA_1s   0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
+#define S_DATA_PIX  0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
+#define S_DATA_PLN  0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
+ one plane of image mem */
+
+/* CREG 3A/CREG 3B */
+#       define RESET_CREG 0x80 /* 1000.0000 */
+
+/* ROP REG  -  all one nibble */
+/*      ********* NOTE : this is used r0,r1,r2,r3 *********** */
+#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
+#define DEST_ZERO               0x0
+#define SRC_AND_DEST    0x1
+#define SRC_AND_nDEST   0x2
+#define SRC                             0x3
+#define nSRC_AND_DEST   0x4
+#define DEST                    0x5
+#define SRC_XOR_DEST    0x6
+#define SRC_OR_DEST             0x7
+#define SRC_NOR_DEST    0x8
+#define SRC_XNOR_DEST   0x9
+#define nDEST                   0xA
+#define SRC_OR_nDEST    0xB
+#define nSRC                    0xC
+#define nSRC_OR_DEST    0xD
+#define SRC_NAND_DEST   0xE
+#define DEST_ONE                0xF
+
+#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
+
+
+void dn_video_setup(char *options, int *ints);
+
+/* frame buffer operations */
+
+static int dn_fb_open(struct fb_info *info,int user);
+static int dn_fb_release(struct fb_info *info,int user);
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, 
+			 struct fb_info *info);
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
+			 struct fb_info *info);
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info);
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info);
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info);
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		       unsigned long arg, int con, struct fb_info *info);
+
+static int dnfbcon_switch(int con,struct fb_info *info);
+static int dnfbcon_updatevar(int con,struct fb_info *info);
+static void dnfbcon_blank(int blank,struct fb_info *info);
+
+static void dn_fb_set_disp(int con,struct fb_info *info);
+
+static struct display disp[MAX_NR_CONSOLES];
+static struct fb_info fb_info;
+static struct fb_ops dn_fb_ops = { 
+	dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var,
+	dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl
+};
+
+static int currcon=0;
+
+#define NUM_TOTAL_MODES 1
+struct fb_var_screeninfo dn_fb_predefined[] = {
+
+	{ 0, },
+
+};
+
+static char dn_fb_name[]="Apollo ";
+
+/* accel stuff */
+#define USE_DN_ACCEL
+
+static struct display_switch dispsw_apollofb;
+
+static int dn_fb_open(struct fb_info *info,int user)
+{
+        /*
+         * Nothing, only a usage count for the moment
+         */
+
+        MOD_INC_USE_COUNT;
+        return(0);
+}
+
+static int dn_fb_release(struct fb_info *info,int user)
+{
+        MOD_DEC_USE_COUNT;
+        return(0);
+}
+
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info) {
+
+	strcpy(fix->id,"Apollo Color4");
+	fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
+	fix->smem_len=FRAME_BUFFER_LEN;
+	fix->type=FB_TYPE_PACKED_PIXELS;
+	fix->type_aux=0;
+	fix->visual=FB_VISUAL_MONO10;
+	fix->xpanstep=0;
+	fix->ypanstep=0;
+	fix->ywrapstep=0;
+        fix->line_length=128;
+
+	return 0;
+
+}
+        
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info) {
+		
+	var->xres=1024;
+	var->yres=800;
+	var->xres_virtual=1024;
+	var->yres_virtual=1024;
+	var->xoffset=0;
+	var->yoffset=0;
+	var->bits_per_pixel=1;
+	var->grayscale=0;
+	var->nonstd=0;
+	var->activate=0;
+	var->height=-1;
+	var->width=-1;
+	var->pixclock=0;
+	var->left_margin=0;
+	var->right_margin=0;
+	var->hsync_len=0;
+	var->vsync_len=0;
+	var->sync=0;
+	var->vmode=FB_VMODE_NONINTERLACED;
+
+	return 0;
+
+}
+
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info) {
+
+        printk("fb_set_var\n");
+	if(var->xres!=1024) 
+		return -EINVAL;
+	if(var->yres!=800)
+		return -EINVAL;
+	if(var->xres_virtual!=1024)
+		return -EINVAL;
+	if(var->yres_virtual!=1024)
+		return -EINVAL;
+	if(var->xoffset!=0)
+		return -EINVAL;
+	if(var->yoffset!=0)
+		return -EINVAL;
+	if(var->bits_per_pixel!=1)
+		return -EINVAL;
+	if(var->grayscale!=0)
+		return -EINVAL;
+	if(var->nonstd!=0)
+		return -EINVAL;
+	if(var->activate!=0)
+		return -EINVAL;
+	if(var->pixclock!=0)
+		return -EINVAL;
+	if(var->left_margin!=0)
+		return -EINVAL;
+	if(var->right_margin!=0)
+		return -EINVAL;
+	if(var->hsync_len!=0)
+		return -EINVAL;
+	if(var->vsync_len!=0)
+		return -EINVAL;
+	if(var->sync!=0)
+		return -EINVAL;
+	if(var->vmode!=FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	return 0;
+
+}
+
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info) {
+
+	printk("get cmap not supported\n");
+
+	return -EINVAL;
+}
+
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info) {
+
+	printk("set cmap not supported\n");
+
+	return -EINVAL;
+
+}
+
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info) {
+
+	printk("panning not supported\n");
+
+	return -EINVAL;
+
+}
+
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		    unsigned long arg, int con, struct fb_info *info) {
+
+	printk("no IOCTLs as of yet.\n");
+
+	return -EINVAL;
+
+}
+
+static void dn_fb_set_disp(int con, struct fb_info *info) {
+
+  struct fb_fix_screeninfo fix;
+  struct display *display;
+
+
+  dn_fb_get_fix(&fix,con, info);
+
+  if (con>=0)
+	display=&fb_display[con];
+  else
+	display=&disp[0];
+
+  if(con==-1) 
+    con=0;
+
+   display->screen_base = (u_char *)fix.smem_start;
+printk("screenbase: %lx\n",fix.smem_start);
+   display->visual = fix.visual;
+   display->type = fix.type;
+   display->type_aux = fix.type_aux;
+   display->ypanstep = fix.ypanstep;
+   display->ywrapstep = fix.ywrapstep;
+   display->can_soft_blank = 1;
+   display->inverse = 0;
+   display->line_length = fix.line_length;
+   display->scrollmode = SCROLL_YREDRAW;
+#ifdef FBCON_HAS_MFB
+   display->dispsw = &fbcon_mfb;
+#else
+   display->dispsw=&fbcon_dummy;
+#endif
+
+}
+  
+unsigned long dnfb_init(unsigned long mem_start) {
+
+	int err;
+
+printk("dn_fb_init\n");
+
+	fb_info.changevar=NULL;
+	strcpy(&fb_info.modename[0],dn_fb_name);
+	fb_info.fontname[0]=0;
+	fb_info.disp=disp;
+	fb_info.switch_con=&dnfbcon_switch;
+	fb_info.updatevar=&dnfbcon_updatevar;
+	fb_info.blank=&dnfbcon_blank;	
+	fb_info.node = -1;
+	fb_info.fbops = &dn_fb_ops;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;	
+
+        dn_fb_get_var(&disp[0].var,0, &fb_info);
+	dn_fb_set_disp(-1, &fb_info);
+
+printk("dn_fb_init: register\n");
+	err=register_framebuffer(&fb_info);
+	if(err < 0) {
+		panic("unable to register apollo frame buffer\n");
+	}
+ 
+	/* now we have registered we can safely setup the hardware */
+
+        outb(RESET_CREG,  AP_CONTROL_3A);
+        outb(NORMAL_MODE, AP_CONTROL_0); 
+        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
+        outb(S_DATA_PLN,  AP_CONTROL_2);
+        outw(SWAP(0x3), AP_ROP_1);
+
+        printk("apollo frame buffer alive and kicking !\n");
+
+
+	return mem_start;
+
+}	
+
+	
+static int dnfbcon_switch(int con,  struct fb_info *info) { 
+
+	currcon=con;
+	
+	return 0;
+
+}
+
+static int dnfbcon_updatevar(int con,  struct fb_info *info) {
+
+	return 0;
+
+}
+
+static void dnfbcon_blank(int blank,  struct fb_info *info) {
+
+	if(blank)  {
+        	outb(0x0,  AP_CONTROL_3A);
+	}
+	else {
+	        outb(0x1,  AP_CONTROL_3A);
+	}
+
+	return ;
+
+}
+
+void dn_video_setup(char *options, int *ints) {
+	
+	return;
+
+}
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+               int x_count, int y_count) {
+
+	int incr,y_delta,pre_read=0,x_end,x_word_count;
+	ushort *src,dummy;
+	uint start_mask,end_mask,dest;
+	short i,j;
+
+	incr=(y_dest<=y_src) ? 1 : -1 ;
+
+	src=(ushort *)(p->screen_base+ y_src*p->next_line+(x_src >> 4));
+	dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
+	
+	if(incr>0) {
+		y_delta=(p->next_line*8)-x_src-x_count;
+		x_end=x_dest+x_count-1;
+		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
+		start_mask=0xffff0000 >> (x_dest & 0xf);
+		end_mask=0x7ffff >> (x_end & 0xf);
+		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
+		if((x_dest & 0xf) < (x_src & 0xf))
+			pre_read=1;
+	}
+	else {
+		y_delta=-((p->next_line*8)-x_src-x_count);
+		x_end=x_dest-x_count+1;
+		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
+		start_mask=0x7ffff >> (x_dest & 0xf);
+		end_mask=0xffff0000 >> (x_end & 0xf);
+		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
+		if((x_dest & 0xf) > (x_src & 0xf))
+			pre_read=1;
+	}
+
+	for(i=0;i<y_count;i++) {
+			
+		if(pre_read) {
+			dummy=*src;
+			src+=incr;
+		}
+
+		if(x_word_count) {
+			outb(start_mask,AP_WRITE_ENABLE);
+			*src=dest;
+			src+=incr;
+			dest+=incr;
+			outb(0,AP_WRITE_ENABLE);
+
+			for(j=1;j<(x_word_count-1);j++) {
+				*src=dest;
+				src+=incr;	
+				dest+=incr;
+			}
+
+			outb(start_mask,AP_WRITE_ENABLE);
+			*src=dest;
+			dest+=incr;
+			src+=incr;
+		}
+		else {
+			outb(start_mask | end_mask, AP_WRITE_ENABLE);
+			*src=dest;
+			dest+=incr;
+			src+=incr;
+		}
+		src+=(y_delta/16);
+		dest+=(y_delta/16);
+	}
+	outb(NORMAL_MODE,AP_CONTROL_0);
+}
+
+static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
+		      int height, int width)
+{
+
+   int fontheight,fontwidth;
+
+    fontheight=fontheight(p);
+    fontwidth=fontwidth(p);
+
+#ifdef USE_DN_ACCEL
+    dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
+	      height*fontheight);
+#else
+    u_char *src, *dest;
+    u_int rows;
+
+    if (sx == 0 && dx == 0 && width == p->next_line) {
+	src = p->screen_base+sy*fontheight*width;
+	dest = p->screen_base+dy*fontheight*width;
+	mymemmove(dest, src, height*fontheight*width);
+    } else if (dy <= sy) {
+	src = p->screen_base+sy*fontheight*p->next_line+sx;
+	dest = p->screen_base+dy*fontheight*p->next_line+dx;
+	for (rows = height*fontheight; rows--;) {
+	    mymemmove(dest, src, width);
+	    src += p->next_line;
+	    dest += p->next_line;
+	}
+    } else {
+	src = p->screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
+	dest = p->screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
+	for (rows = height*fontheight; rows--;) {
+	    mymemmove(dest, src, width);
+	    src -= p->next_line;
+	    dest -= p->next_line;
+	}
+    }
+#endif
+}
+
+static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
+		      int height, int width)
+{
+	fbcon_mfb_clear(conp,p,sy,sx,height,width);
+}
+
+static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
+		     int xx)
+{
+	fbcon_mfb_putc(conp,p,c,yy,xx);
+}
+
+static void putcs_apollofb(struct vc_data *conp, struct display *p, const unsigned short *s,
+		      int count, int yy, int xx)
+{
+	fbcon_mfb_putcs(conp,p,s,count,yy,xx);
+}
+
+static void rev_char_apollofb(struct display *p, int xx, int yy)
+{
+	fbcon_mfb_revc(p,xx,yy);
+}
+
+static struct display_switch dispsw_apollofb = {
+    fbcon_mfb_setup, bmove_apollofb, clear_apollofb,
+    putc_apollofb, putcs_apollofb, rev_char_apollofb
+};
diff -u --recursive --new-file v2.3.41/linux/drivers/video/dn_cfb8.c linux/drivers/video/dn_cfb8.c
--- v2.3.41/linux/drivers/video/dn_cfb8.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/dn_cfb8.c	Mon Jan 31 23:43:51 2000
@@ -0,0 +1,594 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/apollohw.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include "dn_accel.h"
+#include "fbcon.h"
+#include "fbcon-mfb.h"
+
+/* apollo video HW definitions */
+
+/*
+ * Control Registers.   IOBASE + $x
+ *
+ * Note: these are the Memory/IO BASE definitions for a mono card set to the
+ * alternate address
+ *
+ * Control 3A and 3B serve identical functions except that 3A
+ * deals with control 1 and 3b deals with Color LUT reg.
+ */
+
+#define AP_IOBASE       0x3d0          /* Base address of 1 plane board. */
+#define AP_STATUS       isaIO2mem(AP_IOBASE+0) /* Status register.  Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
+#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
+#define AP_ROP_0        isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
+#define AP_ROP_1        isaIO2mem(AP_IOBASE+4) /* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+6) /* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8) /* Control Register 0.  Read/Write */
+#define AP_LUT_DATA     isaIO2mem(AP_IOBASE+9) /* Control Register 0.  Read/Write */
+#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa) /* Control Register 1.  Read/Write */
+#define AP_LUT_CONTROL  isaIO2mem(AP_IOBASE+0xb) /* Control Register 1.  Read/Write */
+#define AP_CONTROL_2A   isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
+#define AP_CONTROL_2B   isaIO2mem(AP_IOBASE+0xd) /* Control Register 2. Read/Write */
+#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
+#define AP_CONTROL_3B   isaIO2mem(AP_IOBASE+0xf) /* Control Register 3a. Read/Write */
+
+
+#define FRAME_BUFFER_START 0x0A0000
+#define FRAME_BUFFER_LEN 0x20000
+
+/* CREG 0 */
+#define VECTOR_MODE 0x40 /* 010x.xxxx */
+#define DBLT_MODE   0x80 /* 100x.xxxx */
+#define NORMAL_MODE 0xE0 /* 111x.xxxx */
+#define SHIFT_BITS  0x1F /* xxx1.1111 */
+        /* other bits are Shift value */
+
+/* CREG 1 */
+#define AD_BLT      0x80 /* 1xxx.xxxx */
+
+#define ROP_EN          0x10 /* xxx1.xxxx */
+#define DST_EQ_SRC      0x00 /* xxx0.xxxx */
+#define nRESET_SYNC     0x08 /* xxxx.1xxx */
+#define SYNC_ENAB       0x02 /* xxxx.xx1x */
+
+#define BLANK_DISP      0x00 /* xxxx.xxx0 */
+#define ENAB_DISP       0x01 /* xxxx.xxx1 */
+
+#define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
+
+/* CREG 2B */
+
+/*
+ * Following 3 defines are common to 1, 4 and 8 plane.
+ */
+
+#define S_DATA_1s   0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
+#define S_DATA_PIX  0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
+#define S_DATA_PLN  0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
+ one plane of image mem */
+
+/* CREG 3A/CREG 3B */
+#       define RESET_CREG 0x80 /* 1000.0000 */
+
+/* ROP REG  -  all one nibble */
+/*      ********* NOTE : this is used r0,r1,r2,r3 *********** */
+#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
+#define DEST_ZERO               0x0
+#define SRC_AND_DEST    0x1
+#define SRC_AND_nDEST   0x2
+#define SRC                             0x3
+#define nSRC_AND_DEST   0x4
+#define DEST                    0x5
+#define SRC_XOR_DEST    0x6
+#define SRC_OR_DEST             0x7
+#define SRC_NOR_DEST    0x8
+#define SRC_XNOR_DEST   0x9
+#define nDEST                   0xA
+#define SRC_OR_nDEST    0xB
+#define nSRC                    0xC
+#define nSRC_OR_DEST    0xD
+#define SRC_NAND_DEST   0xE
+#define DEST_ONE                0xF
+
+#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
+
+
+void dn_video_setup(char *options, int *ints);
+
+/* frame buffer operations */
+
+static int dn_fb_open(struct fb_info *info);
+static int dn_fb_release(struct fb_info *info);
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, 
+			 struct fb_info *info);
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info);
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
+			 struct fb_info *info);
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info);
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info);
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info);
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		       unsigned long arg, int con, struct fb_info *info);
+
+static int dnfbcon_switch(int con,struct fb_info *info);
+static int dnfbcon_updatevar(int con,struct fb_info *info);
+static void dnfbcon_blank(int blank,struct fb_info *info);
+
+static void dn_fb_set_disp(int con,struct fb_info *info);
+
+static struct display disp[MAX_NR_CONSOLES];
+static struct fb_info fb_info;
+static struct fb_ops dn_fb_ops = { 
+	dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var,
+	dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl
+};
+
+static int currcon=0;
+
+#define NUM_TOTAL_MODES 1
+struct fb_var_screeninfo dn_fb_predefined[] = {
+
+	{ 0, },
+
+};
+
+static char dn_fb_name[]="Apollo ";
+
+/* accel stuff */
+#define USE_DN_ACCEL
+
+static struct display_switch dispsw_apollofb;
+
+static int dn_fb_open(struct fb_info *info)
+{
+        /*
+         * Nothing, only a usage count for the moment
+         */
+
+        MOD_INC_USE_COUNT;
+        return(0);
+}
+
+static int dn_fb_release(struct fb_info *info)
+{
+        MOD_DEC_USE_COUNT;
+        return(0);
+}
+
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info) {
+
+	strcpy(fix->id,"Apollo Color8");
+	fix->smem_start=(char*)(FRAME_BUFFER_START+IO_BASE);
+	fix->smem_len=FRAME_BUFFER_LEN;
+	fix->type=FB_TYPE_PACKED_PIXELS;
+	fix->type_aux=0;
+	fix->visual=FB_VISUAL_MONO10;
+	fix->xpanstep=0;
+	fix->ypanstep=0;
+	fix->ywrapstep=0;
+        fix->line_length=128;
+
+	return 0;
+
+}
+        
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info) {
+		
+	var->xres=1024;
+	var->yres=800;
+	var->xres_virtual=1024;
+	var->yres_virtual=1024;
+	var->xoffset=0;
+	var->yoffset=0;
+	var->bits_per_pixel=1;
+	var->grayscale=0;
+	var->nonstd=0;
+	var->activate=0;
+	var->height=-1;
+	var->width=-1;
+	var->pixclock=0;
+	var->left_margin=0;
+	var->right_margin=0;
+	var->hsync_len=0;
+	var->vsync_len=0;
+	var->sync=0;
+	var->vmode=FB_VMODE_NONINTERLACED;
+
+	return 0;
+
+}
+
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info) {
+
+        printk("fb_set_var\n");
+	if(var->xres!=1024) 
+		return -EINVAL;
+	if(var->yres!=800)
+		return -EINVAL;
+	if(var->xres_virtual!=1024)
+		return -EINVAL;
+	if(var->yres_virtual!=1024)
+		return -EINVAL;
+	if(var->xoffset!=0)
+		return -EINVAL;
+	if(var->yoffset!=0)
+		return -EINVAL;
+	if(var->bits_per_pixel!=1)
+		return -EINVAL;
+	if(var->grayscale!=0)
+		return -EINVAL;
+	if(var->nonstd!=0)
+		return -EINVAL;
+	if(var->activate!=0)
+		return -EINVAL;
+	if(var->pixclock!=0)
+		return -EINVAL;
+	if(var->left_margin!=0)
+		return -EINVAL;
+	if(var->right_margin!=0)
+		return -EINVAL;
+	if(var->hsync_len!=0)
+		return -EINVAL;
+	if(var->vsync_len!=0)
+		return -EINVAL;
+	if(var->sync!=0)
+		return -EINVAL;
+	if(var->vmode!=FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	return 0;
+
+}
+
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info) {
+
+	printk("get cmap not supported\n");
+
+	return -EINVAL;
+}
+
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info) {
+
+	printk("set cmap not supported\n");
+
+	return -EINVAL;
+
+}
+
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info) {
+
+	printk("panning not supported\n");
+
+	return -EINVAL;
+
+}
+
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		    unsigned long arg, int con, struct fb_info *info) {
+
+	printk("no IOCTLs as of yet.\n");
+
+	return -EINVAL;
+
+}
+
+static void dn_fb_set_disp(int con, struct fb_info *info) {
+
+  struct fb_fix_screeninfo fix;
+
+  dn_fb_get_fix(&fix,con, info);
+  if(con==-1) 
+    con=0;
+
+   disp[con].screen_base = (u_char *)fix.smem_start;
+printk("screenbase: %p\n",fix.smem_start);
+   disp[con].visual = fix.visual;
+   disp[con].type = fix.type;
+   disp[con].type_aux = fix.type_aux;
+   disp[con].ypanstep = fix.ypanstep;
+   disp[con].ywrapstep = fix.ywrapstep;
+   disp[con].can_soft_blank = 1;
+   disp[con].inverse = 0;
+   disp[con].line_length = fix.line_length;
+   disp[con].dispsw = &dispsw_apollofb;
+}
+  
+unsigned long dn_fb_init(unsigned long mem_start) {
+
+	int err;
+       
+printk("dn_fb_init\n");
+
+	fb_info.changevar=NULL;
+	strcpy(&fb_info.modename[0],dn_fb_name);
+	fb_info.fontname[0]=0;
+	fb_info.disp=disp;
+	fb_info.switch_con=&dnfbcon_switch;
+	fb_info.updatevar=&dnfbcon_updatevar;
+	fb_info.blank=&dnfbcon_blank;	
+	fb_info.node = -1;
+	fb_info.fbops = &dn_fb_ops;
+	
+printk("dn_fb_init: register\n");
+	err=register_framebuffer(&fb_info);
+	if(err < 0) {
+		panic("unable to register apollo frame buffer\n");
+	}
+ 
+	/* now we have registered we can safely setup the hardware */
+
+        outb(RESET_CREG,  AP_CONTROL_3A);
+        outb(RESET_CREG,  AP_CONTROL_3B);
+        outw(0x0,  AP_WRITE_ENABLE);
+        outb(NORMAL_MODE, AP_CONTROL_0); 
+        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
+        outb(0,  AP_CONTROL_2A);
+        outb(S_DATA_PLN,  AP_CONTROL_2B);
+        outw(SWAP(0x3), AP_ROP_1);
+
+        printk("apollo frame buffer alive and kicking !\n");
+
+        dn_fb_get_var(&disp[0].var,0, &fb_info);
+
+	dn_fb_set_disp(-1, &fb_info);
+
+	return mem_start;
+
+}	
+
+	
+static int dnfbcon_switch(int con,  struct fb_info *info) { 
+
+	currcon=con;
+	
+	return 0;
+
+}
+
+static int dnfbcon_updatevar(int con,  struct fb_info *info) {
+
+	return 0;
+
+}
+
+static void dnfbcon_blank(int blank,  struct fb_info *info) {
+
+	if(blank)  {
+        	outb(0x0,  AP_CONTROL_3A);
+	}
+	else {
+	        outb(0x1,  AP_CONTROL_3A);
+	}
+
+	return ;
+
+}
+
+void dn_video_setup(char *options, int *ints) {
+	
+	return;
+
+}
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+               int x_count, int y_count) {
+
+	int incr,y_delta,pre_read=0,x_end,x_word_count;
+	ushort *src,dummy;
+	uint start_mask,end_mask,dest;
+	short i,j;
+
+	incr=(y_dest<=y_src) ? 1 : -1 ;
+
+	src=(ushort *)(p->screen_base+ y_src*p->next_line+(x_src >> 4));
+	dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
+	
+	if(incr>0) {
+		y_delta=(p->next_line*8)-x_src-x_count;
+		x_end=x_dest+x_count-1;
+		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
+		start_mask=0xffff0000 >> (x_dest & 0xf);
+		end_mask=0x7ffff >> (x_end & 0xf);
+		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
+		if((x_dest & 0xf) < (x_src & 0xf))
+			pre_read=1;
+	}
+	else {
+		y_delta=-((p->next_line*8)-x_src-x_count);
+		x_end=x_dest-x_count+1;
+		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
+		start_mask=0x7ffff >> (x_dest & 0xf);
+		end_mask=0xffff0000 >> (x_end & 0xf);
+		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
+		if((x_dest & 0xf) > (x_src & 0xf))
+			pre_read=1;
+	}
+
+	for(i=0;i<y_count;i++) {
+			
+		if(pre_read) {
+			dummy=*src;
+			src+=incr;
+		}
+
+		if(x_word_count) {
+			outb(start_mask,AP_WRITE_ENABLE);
+			*src=dest;
+			src+=incr;
+			dest+=incr;
+			outb(0,AP_WRITE_ENABLE);
+
+			for(j=1;j<(x_word_count-1);j++) {
+				*src=dest;
+				src+=incr;	
+				dest+=incr;
+			}
+
+			outb(start_mask,AP_WRITE_ENABLE);
+			*src=dest;
+			dest+=incr;
+			src+=incr;
+		}
+		else {
+			outb(start_mask | end_mask, AP_WRITE_ENABLE);
+			*src=dest;
+			dest+=incr;
+			src+=incr;
+		}
+		src+=(y_delta/16);
+		dest+=(y_delta/16);
+	}
+	outb(NORMAL_MODE,AP_CONTROL_0);
+}
+
+static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
+		      int height, int width)
+{
+
+#ifdef USE_DN_ACCEL
+    dn_bitblt(p,sx,sy*p->fontheight,dx,dy*p->fontheight,width*p->fontwidth,
+	      height*p->fontheight);
+#else
+    u_char *src, *dest;
+    u_int rows;
+
+    if (sx == 0 && dx == 0 && width == p->next_line) {
+	src = p->screen_base+sy*p->fontheight*width;
+	dest = p->screen_base+dy*p->fontheight*width;
+	mymemmove(dest, src, height*p->fontheight*width);
+    } else if (dy <= sy) {
+	src = p->screen_base+sy*p->fontheight*p->next_line+sx;
+	dest = p->screen_base+dy*p->fontheight*p->next_line+dx;
+	for (rows = height*p->fontheight; rows--;) {
+	    mymemmove(dest, src, width);
+	    src += p->next_line;
+	    dest += p->next_line;
+	}
+    } else {
+	src = p->screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx;
+	dest = p->screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx;
+	for (rows = height*p->fontheight; rows--;) {
+	    mymemmove(dest, src, width);
+	    src -= p->next_line;
+	    dest -= p->next_line;
+	}
+    }
+#endif
+}
+
+static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
+		      int height, int width)
+{
+    u_char *dest;
+    u_int rows;
+
+    dest = p->screen_base+sy*p->fontheight*p->next_line+sx;
+
+    if (sx == 0 && width == p->next_line)
+	if (attr_reverse(p,conp))
+	    mymemset(dest, height*p->fontheight*width);
+	else
+	    mymemclear(dest, height*p->fontheight*width);
+    else
+	for (rows = height*p->fontheight; rows--; dest += p->next_line)
+	    if (attr_reverse(p,conp))
+		mymemset(dest, width);
+	    else
+		mymemclear_small(dest, width);
+}
+
+static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
+		     int xx)
+{
+    u_char *dest, *cdat;
+    u_int rows, bold, revs, underl;
+    u_char d;
+
+    c &= 0xff;
+
+    dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
+    cdat = p->fontdata+c*p->fontheight;
+    bold = attr_bold(p,conp);
+    revs = attr_reverse(p,conp);
+    underl = attr_underline(p,conp);
+
+    for (rows = p->fontheight; rows--; dest += p->next_line) {
+	d = *cdat++;
+	if (underl && !rows)
+	    d = 0xff;
+	else if (bold)
+	    d |= d>>1;
+	if (revs)
+	    d = ~d;
+	*dest = d;
+    }
+}
+
+static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
+		      int count, int yy, int xx)
+{
+    u_char *dest, *dest0, *cdat;
+    u_int rows, bold, revs, underl;
+    u_char c, d;
+
+    dest0 = p->screen_base+yy*p->fontheight*p->next_line+xx;
+    bold = attr_bold(p,conp);
+    revs = attr_reverse(p,conp);
+    underl = attr_underline(p,conp);
+
+    while (count--) {
+	c = *s++;
+	dest = dest0++;
+	cdat = p->fontdata+c*p->fontheight;
+	for (rows = p->fontheight; rows--; dest += p->next_line) {
+	    d = *cdat++;
+	    if (underl && !rows)
+		d = 0xff;
+	    else if (bold)
+		d |= d>>1;
+	    if (revs)
+		d = ~d;
+	    *dest = d;
+	}
+    }
+}
+
+static void rev_char_apollofb(struct display *p, int xx, int yy)
+{
+    u_char *dest;
+    u_int rows;
+
+    dest = p->screen_base+yy*p->fontheight*p->next_line+xx;
+    for (rows = p->fontheight; rows--; dest += p->next_line)
+	*dest = ~*dest;
+}
+
+static struct display_switch dispsw_apollofb = {
+    fbcon_mfb_setup, bmove_apollofb, clear_apollofb,
+    putc_apollofb, putcs_apollofb, rev_char_apollofb
+};
diff -u --recursive --new-file v2.3.41/linux/drivers/video/dnfb.c linux/drivers/video/dnfb.c
--- v2.3.41/linux/drivers/video/dnfb.c	Tue Dec  7 09:32:46 1999
+++ linux/drivers/video/dnfb.c	Tue Feb  1 01:31:04 2000
@@ -10,14 +10,15 @@
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
 #include <asm/apollohw.h>
 #include <linux/fb.h>
 #include <linux/module.h>
-
+#include "dn_accel.h"
 #include <video/fbcon.h>
 #include <video/fbcon-mfb.h>
 
-
 /* apollo video HW definitions */
 
 /*
@@ -30,16 +31,16 @@
  * deals with control 1 and 3b deals with Color LUT reg.
  */
 
-#define AP_IOBASE       0x5d80          /* Base address of 1 plane board. */
-#define AP_STATUS       0x5d80          /* Status register.  Read */
-#define AP_WRITE_ENABLE 0x5d80          /* Write Enable Register Write */
-#define AP_DEVICE_ID    0x5d81          /* Device ID Register. Read */
-#define AP_ROP_1        0x5d82          /* Raster Operation reg. Write Word */
-#define AP_DIAG_MEM_REQ 0x5d84          /* Diagnostic Memory Request. Write Word */
-#define AP_CONTROL_0    0x5d88          /* Control Register 0.  Read/Write */
-#define AP_CONTROL_1    0x5d8a          /* Control Register 1.  Read/Write */
-#define AP_CONTROL_3A   0x5d8e          /* Control Register 3a. Read/Write */
-#define AP_CONTROL_2    0x5d8c          /* Control Register 2. Read/Write */
+#define AP_IOBASE       0x3b0          /* Base address of 1 plane board. */
+#define AP_STATUS       isaIO2mem(AP_IOBASE+0) /* Status register.  Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
+#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
+#define AP_ROP_1        isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8) /* Control Register 0.  Read/Write */
+#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa) /* Control Register 1.  Read/Write */
+#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
+#define AP_CONTROL_2    isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
 
 
 #define FRAME_BUFFER_START 0x0FA0000
@@ -112,44 +113,57 @@
 #endif
 
 
+void dn_video_setup(char *options, int *ints);
+
 /* frame buffer operations */
 
-static int dnfb_open(struct fb_info *info, int user);
-static int dnfb_release(struct fb_info *info, int user);
-static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			struct fb_info *info);
-static int dnfb_get_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info);
-static int dnfb_set_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info);
-static int dnfb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+static int dn_fb_open(struct fb_info *info,int user);
+static int dn_fb_release(struct fb_info *info,int user);
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, 
 			 struct fb_info *info);
-static int dnfb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info);
-static int dnfb_pan_display(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info);
-static int dnfb_ioctl(struct inode *inode, struct file *file,
-		      unsigned int cmd, unsigned long arg, int con,
-		      struct fb_info *info);
-
-static int dnfbcon_switch(int con, struct fb_info *info);
-static int dnfbcon_updatevar(int con, struct fb_info *info);
-static void dnfbcon_blank(int blank, struct fb_info *info);
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
+			 struct fb_info *info);
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info);
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info);
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info);
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		       unsigned long arg, int con, struct fb_info *info);
+
+static int dnfbcon_switch(int con,struct fb_info *info);
+static int dnfbcon_updatevar(int con,struct fb_info *info);
+static void dnfbcon_blank(int blank,struct fb_info *info);
 
-static void dnfb_set_disp(int con, struct fb_info *info);
+static void dn_fb_set_disp(int con,struct fb_info *info);
 
 static struct display disp[MAX_NR_CONSOLES];
 static struct fb_info fb_info;
-static struct fb_ops dnfb_ops = { 
-	dnfb_open,dnfb_release, dnfb_get_fix, dnfb_get_var, dnfb_set_var,
-	dnfb_get_cmap, dnfb_set_cmap, dnfb_pan_display, dnfb_ioctl
+static struct fb_ops dn_fb_ops = { 
+	dn_fb_open,dn_fb_release, dn_fb_get_fix, dn_fb_get_var, dn_fb_set_var,
+	dn_fb_get_cmap, dn_fb_set_cmap, dn_fb_pan_display, dn_fb_ioctl
 };
 
 static int currcon=0;
 
-static char dnfb_name[]="Apollo";
+#define NUM_TOTAL_MODES 1
+struct fb_var_screeninfo dn_fb_predefined[] = {
+
+	{ 0, },
+
+};
+
+static char dn_fb_name[]="Apollo ";
+
+/* accel stuff */
+#define USE_DN_ACCEL
 
-static int dnfb_open(struct fb_info *info, int user)
+static struct display_switch dispsw_apollofb;
+
+static int dn_fb_open(struct fb_info *info,int user)
 {
         /*
          * Nothing, only a usage count for the moment
@@ -159,18 +173,17 @@
         return(0);
 }
 
-static int dnfb_release(struct fb_info *info, int user)
+static int dn_fb_release(struct fb_info *info,int user)
 {
         MOD_DEC_USE_COUNT;
         return(0);
 }
 
-static int dnfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			struct fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info) {
+
 	strcpy(fix->id,"Apollo Mono");
-	fix->smem_start=FRAME_BUFFER_START+IO_BASE;
+	fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
 	fix->smem_len=FRAME_BUFFER_LEN;
 	fix->type=FB_TYPE_PACKED_PIXELS;
 	fix->type_aux=0;
@@ -184,10 +197,9 @@
 
 }
         
-static int dnfb_get_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info)
-{
-	memset(var, 0, sizeof(struct fb_var_screeninfo));
+static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info) {
+		
 	var->xres=1280;
 	var->yres=1024;
 	var->xres_virtual=2048;
@@ -212,9 +224,10 @@
 
 }
 
-static int dnfb_set_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info)
-{
+static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info) {
+
+        printk("fb_set_var\n");
 	if(var->xres!=1280) 
 		return -EINVAL;
 	if(var->yres!=1024)
@@ -254,119 +267,284 @@
 
 }
 
-static int dnfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			 struct fb_info *info)
-{
+static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info) {
+
 	printk("get cmap not supported\n");
 
 	return -EINVAL;
 }
 
-static int dnfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			 struct fb_info *info)
-{
+static int dn_fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
+			  struct fb_info *info) {
+
 	printk("set cmap not supported\n");
 
 	return -EINVAL;
 
 }
 
-static int dnfb_pan_display(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info)
-{
+static int dn_fb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *info) {
+
 	printk("panning not supported\n");
 
 	return -EINVAL;
 
 }
 
-static int dnfb_ioctl(struct inode *inode, struct file *file,
-		      unsigned int cmd, unsigned long arg, int con,
-		      struct fb_info *info)
-{
+static int dn_fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		    unsigned long arg, int con, struct fb_info *info) {
+
+	printk("no IOCTLs as of yet.\n");
+
 	return -EINVAL;
+
 }
 
-static void dnfb_set_disp(int con, struct fb_info *info)
-{
+static void dn_fb_set_disp(int con, struct fb_info *info) {
+
   struct fb_fix_screeninfo fix;
+  struct display *display;
+  
+  dn_fb_get_fix(&fix,con, info);
+
+  if (con>=0)
+	display=&fb_display[con];
+  else
+	display=&disp[0];
 
-  dnfb_get_fix(&fix, con, info);
   if(con==-1) 
     con=0;
 
-   disp[con].screen_base = fix.smem_start;
-   disp[con].visual = fix.visual;
-   disp[con].type = fix.type;
-   disp[con].type_aux = fix.type_aux;
-   disp[con].ypanstep = fix.ypanstep;
-   disp[con].ywrapstep = fix.ywrapstep;
-   disp[con].can_soft_blank = 1;
-   disp[con].inverse = 0;
-   disp[con].line_length = fix.line_length;
+   display->screen_base = (u_char *)fix.smem_start;
+   display->visual = fix.visual;
+   display->type = fix.type;
+   display->type_aux = fix.type_aux;
+   display->ypanstep = fix.ypanstep;
+   display->ywrapstep = fix.ywrapstep;
+   display->can_soft_blank = 1;
+   display->inverse = 0;
+   display->line_length = fix.line_length;
 #ifdef FBCON_HAS_MFB
-   disp[con].dispsw = &fbcon_mfb;
+   display->dispsw = &fbcon_mfb;
 #else
-   disp[con].dispsw = &fbcon_dummy;
+   display->dispsw=&fbcon_dummy;
 #endif
+
 }
   
-int dnfb_init(void)
-{
+unsigned long dnfb_init(unsigned long mem_start) {
+
+	int err;
+       
+
 	fb_info.changevar=NULL;
-	strcpy(&fb_info.modename[0],dnfb_name);
+	strcpy(&fb_info.modename[0],dn_fb_name);
 	fb_info.fontname[0]=0;
 	fb_info.disp=disp;
 	fb_info.switch_con=&dnfbcon_switch;
 	fb_info.updatevar=&dnfbcon_updatevar;
 	fb_info.blank=&dnfbcon_blank;	
 	fb_info.node = -1;
-	fb_info.fbops = &dnfb_ops;
-	fb_info.flags = FBINFO_FLAG_DEFAULT;
+	fb_info.fbops = &dn_fb_ops;
 	
-        outb(RESET_CREG, AP_CONTROL_3A);
-        outw(0x0, AP_WRITE_ENABLE);
-        outb(NORMAL_MODE,AP_CONTROL_0); 
-        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
-        outb(S_DATA_PLN, AP_CONTROL_2);
-        outw(SWAP(0x3),AP_ROP_1);
-
-        dnfb_get_var(&disp[0].var, 0, &fb_info);
-	dnfb_set_disp(-1, &fb_info);
+        dn_fb_get_var(&disp[0].var,0, &fb_info);
 
-	if (register_framebuffer(&fb_info) < 0) {
-		printk(KERN_ERR "unable to register apollo frame buffer\n");
-		return -EINVAL;
+	dn_fb_set_disp(-1, &fb_info);
+	
+	err=register_framebuffer(&fb_info);
+	if(err < 0) {
+		panic("unable to register apollo frame buffer\n");
 	}
  
-        printk("fb%d: apollo frame buffer alive and kicking !\n",
-	       GET_FB_IDX(fb_info.node));
-	return 0;
+	/* now we have registered we can safely setup the hardware */
+
+        outb(RESET_CREG,  AP_CONTROL_3A);
+        outw(0x0,  AP_WRITE_ENABLE);
+        outb(NORMAL_MODE, AP_CONTROL_0); 
+        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
+        outb(S_DATA_PLN,  AP_CONTROL_2);
+        outw(SWAP(0x3), AP_ROP_1);
+
+        printk("apollo frame buffer alive and kicking !\n");
+
+
+	return mem_start;
+
 }	
 
 	
-static int dnfbcon_switch(int con, struct fb_info *info)
-{ 
+static int dnfbcon_switch(int con,  struct fb_info *info) { 
+
 	currcon=con;
 	
 	return 0;
 
 }
 
-static int dnfbcon_updatevar(int con, struct fb_info *info)
-{
+static int dnfbcon_updatevar(int con,  struct fb_info *info) {
+
 	return 0;
+
 }
 
-static void dnfbcon_blank(int blank, struct fb_info *info)
-{
+static void dnfbcon_blank(int blank,  struct fb_info *info) {
+
 	if(blank)  {
-        	outb(0, AP_CONTROL_3A);
-		outb((AD_BLT | DST_EQ_SRC | NORM_CREG1) & ~ENAB_DISP,
-		     AP_CONTROL_1);
+        	outb(0x0,  AP_CONTROL_3A);
 	}
 	else {
-	        outb(1, AP_CONTROL_3A);
-        	outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
+	        outb(0x1,  AP_CONTROL_3A);
 	}
+
+	return ;
+
+}
+
+void dn_video_setup(char *options, int *ints) {
+	
+	return;
+
 }
+
+void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
+               int x_count, int y_count) {
+
+	int incr,y_delta,pre_read=0,x_end,x_word_count;
+	ushort *src,dummy;
+	uint start_mask,end_mask,dest;
+	short i,j;
+
+	incr=(y_dest<=y_src) ? 1 : -1 ;
+
+	src=(ushort *)(p->screen_base+ y_src*p->next_line+(x_src >> 4));
+	dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
+	
+	if(incr>0) {
+		y_delta=(p->next_line*8)-x_src-x_count;
+		x_end=x_dest+x_count-1;
+		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
+		start_mask=0xffff0000 >> (x_dest & 0xf);
+		end_mask=0x7ffff >> (x_end & 0xf);
+		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
+		if((x_dest & 0xf) < (x_src & 0xf))
+			pre_read=1;
+	}
+	else {
+		y_delta=-((p->next_line*8)-x_src-x_count);
+		x_end=x_dest-x_count+1;
+		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
+		start_mask=0x7ffff >> (x_dest & 0xf);
+		end_mask=0xffff0000 >> (x_end & 0xf);
+		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
+		if((x_dest & 0xf) > (x_src & 0xf))
+			pre_read=1;
+	}
+
+	for(i=0;i<y_count;i++) {
+
+		outb(0xc | (dest >> 16), AP_CONTROL_3A);
+			
+		if(pre_read) {
+			dummy=*src;
+			src+=incr;
+		}
+
+		if(x_word_count) {
+			outb(start_mask,AP_WRITE_ENABLE);
+			*src=dest;
+			src+=incr;
+			dest+=incr;
+			outb(0,AP_WRITE_ENABLE);
+
+			for(j=1;j<(x_word_count-1);j++) {
+				*src=dest;
+				src+=incr;	
+				dest+=incr;
+			}
+
+			outb(start_mask,AP_WRITE_ENABLE);
+			*src=dest;
+			dest+=incr;
+			src+=incr;
+		}
+		else {
+			outb(start_mask | end_mask, AP_WRITE_ENABLE);
+			*src=dest;
+			dest+=incr;
+			src+=incr;
+		}
+		src+=(y_delta/16);
+		dest+=(y_delta/16);
+	}
+	outb(NORMAL_MODE,AP_CONTROL_0);
+}
+
+static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
+		      int height, int width)
+{
+
+    int fontheight,fontwidth;
+
+    fontheight=fontheight(p);
+    fontwidth=fontwidth(p);
+
+#ifdef USE_DN_ACCEL
+    dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
+	      height*fontheight);
+#else
+    u_char *src, *dest;
+    u_int rows;
+
+    if (sx == 0 && dx == 0 && width == p->next_line) {
+	src = p->screen_base+sy*fontheight*width;
+	dest = p->screen_base+dy*fontheight*width;
+	mymemmove(dest, src, height*fontheight*width);
+    } else if (dy <= sy) {
+	src = p->screen_base+sy*fontheight*next_line+sx;
+	dest = p->screen_base+dy*fontheight*next_line+dx;
+	for (rows = height*fontheight; rows--;) {
+	    mymemmove(dest, src, width);
+	    src += p->next_line;
+	    dest += p->next_line;
+	}
+    } else {
+	src = p->screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
+	dest = p->screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
+	for (rows = height*fontheight; rows--;) {
+	    mymemmove(dest, src, width);
+	    src -= p->next_line;
+	    dest -= p->next_line;
+	}
+    }
+#endif
+}
+
+static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
+		      int height, int width)
+{
+	fbcon_mfb_clear(conp,p,sy,sx,height,width);
+}
+
+static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
+		     int xx)
+{
+	fbcon_mfb_putc(conp,p,c,yy,xx);
+}
+
+static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
+		      int count, int yy, int xx)
+{
+	fbcon_mfb_putcs(conp,p,s,count,yy,xx);
+}
+
+static void rev_char_apollofb(struct display *p, int xx, int yy)
+{
+	fbcon_mfb_revc(p,xx,yy);
+}
+
+static struct display_switch dispsw_apollofb = {
+    fbcon_mfb_setup, bmove_apollofb, clear_apollofb,
+    putc_apollofb, putcs_apollofb, rev_char_apollofb
+};
diff -u --recursive --new-file v2.3.41/linux/fs/autofs4/inode.c linux/fs/autofs4/inode.c
--- v2.3.41/linux/fs/autofs4/inode.c	Fri Jan 28 15:09:08 2000
+++ linux/fs/autofs4/inode.c	Mon Jan 31 10:19:46 2000
@@ -140,7 +140,7 @@
 	*gid = current->gid;
 	*pgrp = current->pgrp;
 
-	*minproto = *maxproto = AUTOFS_PROTO_VERSION;
+	*minproto = *maxproto = AUTOFS_MAX_PROTO_VERSION;
 
 	*pipefd = -1;
 
@@ -278,15 +278,15 @@
 
 	/* Couldn't this be tested earlier? */
 	if (maxproto < AUTOFS_MIN_PROTO_VERSION ||
-	    minproto > AUTOFS_PROTO_VERSION) {
+	    minproto > AUTOFS_MAX_PROTO_VERSION) {
 		printk("autofs: kernel does not match daemon version "
 		       "daemon (%d, %d) kernel (%d, %d)\n",
 			minproto, maxproto,
-			AUTOFS_MIN_PROTO_VERSION, AUTOFS_PROTO_VERSION);
+			AUTOFS_MIN_PROTO_VERSION, AUTOFS_MAX_PROTO_VERSION);
 		goto fail_dput;
 	}
 
-	sbi->version = maxproto > AUTOFS_PROTO_VERSION ? AUTOFS_PROTO_VERSION : maxproto;
+	sbi->version = maxproto > AUTOFS_MAX_PROTO_VERSION ? AUTOFS_MAX_PROTO_VERSION : maxproto;
 
 	DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
 	pipe = fget(pipefd);
diff -u --recursive --new-file v2.3.41/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.3.41/linux/fs/nfsd/export.c	Fri Jan 21 18:19:17 2000
+++ linux/fs/nfsd/export.c	Mon Jan 31 10:14:45 2000
@@ -611,6 +611,7 @@
 	{ NFSEXP_SUNSECURE, { "sunsecure", ""}},
 	{ NFSEXP_CROSSMNT, {"nohide", ""}},
 	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
+	{ NFSEXP_NOAUTHNLM, {"no_auth_nlm", ""}},
 	{ 0, {"", ""}}
 };
 
diff -u --recursive --new-file v2.3.41/linux/fs/nfsd/lockd.c linux/fs/nfsd/lockd.c
--- v2.3.41/linux/fs/nfsd/lockd.c	Mon Aug 31 11:03:38 1998
+++ linux/fs/nfsd/lockd.c	Mon Jan 31 10:14:45 2000
@@ -30,7 +30,7 @@
 	fh.fh_handle = *f;
 	fh.fh_export = NULL;
 
-	nfserr = nfsd_open(rqstp, &fh, S_IFREG, 0, filp);
+	nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
 	if (!nfserr)
 		dget(filp->f_dentry);
 	fh_put(&fh);
diff -u --recursive --new-file v2.3.41/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.3.41/linux/fs/nfsd/nfsproc.c	Fri Jan 21 18:19:17 2000
+++ linux/fs/nfsd/nfsproc.c	Mon Jan 31 10:14:45 2000
@@ -391,10 +391,6 @@
 						 argp->tname, argp->tlen,
 				 		 &newfh, &argp->attrs);
 
-	if (!nfserr) {
-		argp->attrs.ia_valid &= ~ATTR_SIZE;
-		nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs);
-	}
 
 	fh_put(&argp->ffh);
 	fh_put(&newfh);
diff -u --recursive --new-file v2.3.41/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.41/linux/fs/nfsd/vfs.c	Fri Jan 21 18:19:17 2000
+++ linux/fs/nfsd/vfs.c	Mon Jan 31 16:33:32 2000
@@ -46,19 +46,12 @@
 #define NFSDDBG_FACILITY		NFSDDBG_FILEOP
 #define NFSD_PARANOIA
 
-/* Open mode for nfsd_open */
-#define OPEN_READ	0
-#define OPEN_WRITE	1
-
-/* Hack until we have a macro check for mandatory locks. */
-#ifndef IS_ISMNDLK
-/* We must ignore files (but only file) which might have mandatory
+
+/* We must ignore files (but only files) which might have mandatory
  * locks on them because there is no way to know if the accesser has
  * the lock.
  */
-#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_IXGRP|S_IFMT)) \
-			 == (S_ISGID|S_IFREG))
-#endif
+#define IS_ISMNDLK(i)	(S_ISREG((i)->i_mode) && MANDATORY_LOCK(i))
 
 /* Check for dir entries '.' and '..' */
 #define isdotent(n, l)	(l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
@@ -427,18 +420,17 @@
 
 /*
  * Open an existing file or directory.
- * The wflag argument indicates write access.
+ * The access argument indicates the type of open (read/write/lock)
  * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
-			int wflag, struct file *filp)
+			int access, struct file *filp)
 {
 	struct dentry	*dentry;
 	struct inode	*inode;
-	int		access, err;
+	int		err;
 
-	access = wflag? MAY_WRITE : MAY_READ;
 	err = fh_verify(rqstp, fhp, type, access);
 	if (err)
 		goto out;
@@ -455,24 +447,27 @@
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		goto out;
 
-	if (wflag && (err = get_write_access(inode)) != 0)
+	if ((access & MAY_WRITE) && (err = get_write_access(inode)) != 0)
 		goto out_nfserr;
 
 	memset(filp, 0, sizeof(*filp));
 	filp->f_op    = inode->i_op->default_file_ops;
 	atomic_set(&filp->f_count, 1);
-	filp->f_flags = wflag? O_WRONLY : O_RDONLY;
-	filp->f_mode  = wflag? FMODE_WRITE : FMODE_READ;
 	filp->f_dentry = dentry;
-
-	if (wflag)
+	if (access & MAY_WRITE) {
+		filp->f_flags = O_WRONLY;
+		filp->f_mode  = FMODE_WRITE;
 		DQUOT_INIT(inode);
+	} else {
+		filp->f_flags = O_RDONLY;
+		filp->f_mode  = FMODE_READ;
+	}
 
 	err = 0;
 	if (filp->f_op && filp->f_op->open) {
 		err = filp->f_op->open(inode, filp);
 		if (err) {
-			if (wflag)
+			if (access & MAY_WRITE)
 				put_write_access(inode);
 
 			/* I nearly added put_filp() call here, but this filp
@@ -581,7 +576,7 @@
 	int		err;
 	struct file	file;
 
-	err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file);
+	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file);
 	if (err)
 		goto out;
 	err = nfserr_perm;
@@ -648,7 +643,7 @@
 
 	if (!cnt)
 		goto out;
-	err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file);
+	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
 	if (err)
 		goto out;
 	err = nfserr_perm;
@@ -774,7 +769,7 @@
 	struct file	file;
 	int		err;
 
-	if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file)) != 0)
+	if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0)
 		return err;
 
 	if (file.f_op && file.f_op->fsync) {
@@ -1204,6 +1199,8 @@
 				iap->ia_valid &= ATTR_MODE /* ~(ATTR_MODE|ATTR_UID|ATTR_GID)*/;
 				if (iap->ia_valid) {
 					iap->ia_valid |= ATTR_CTIME;
+					iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+						| S_IFLNK;
 					err = notify_change(dnew, iap);
 					if (!err && EX_ISSYNC(fhp->fh_export))
 						write_inode_now(dentry->d_inode);
@@ -1532,7 +1529,7 @@
 	if (offset > ~(u32) 0)
 		goto out;
 
-	err = nfsd_open(rqstp, fhp, S_IFDIR, OPEN_READ, &file);
+	err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);
 	if (err)
 		goto out;
 
@@ -1650,13 +1647,14 @@
 	if (acc == MAY_NOP)
 		return 0;
 #if 0
-	dprintk("nfsd: permission 0x%x%s%s%s%s%s mode 0%o%s%s%s\n",
+	dprintk("nfsd: permission 0x%x%s%s%s%s%s%s mode 0%o%s%s%s\n",
 		acc,
 		(acc & MAY_READ)?	" read"  : "",
 		(acc & MAY_WRITE)?	" write" : "",
 		(acc & MAY_EXEC)?	" exec"  : "",
 		(acc & MAY_SATTR)?	" sattr" : "",
 		(acc & MAY_TRUNC)?	" trunc" : "",
+		(acc & MAY_LOCK)?	" lock"  : "",
 		inode->i_mode,
 		IS_IMMUTABLE(inode)?	" immut" : "",
 		IS_APPEND(inode)?	" append" : "",
@@ -1674,6 +1672,15 @@
 	if ((acc & MAY_TRUNC) && IS_APPEND(inode))
 		return nfserr_perm;
 
+	if (acc & MAY_LOCK) {
+		/* If we cannot rely on authentication in NLM requests,
+		 * just allow locks, others require read permission
+		 */
+		if (exp->ex_flags & NFSEXP_NOAUTHNLM)
+			return 0;
+		else
+			acc = MAY_READ;
+	}
 	/*
 	 * The file owner always gets access permission. This is to make
 	 * file access work even when the client has done a fchmod(fd, 0).
diff -u --recursive --new-file v2.3.41/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.3.41/linux/fs/proc/base.c	Fri Jan  7 19:13:22 2000
+++ linux/fs/proc/base.c	Mon Jan 31 23:37:19 2000
@@ -498,9 +498,6 @@
 	PROC_PID_STAT,
 	PROC_PID_STATM,
 	PROC_PID_MAPS,
-#if CONFIG_AP1000
-	PROC_PID_RINGBUF,
-#endif
 	PROC_PID_CPU,
 	PROC_PID_FD_DIR = 0x8000,	/* 0x8000-0xffff */
 };
@@ -516,9 +513,6 @@
 #ifdef __SMP__
   E(PROC_PID_CPU,	"cpu",		S_IFREG|S_IRUGO),
 #endif
-#if CONFIG_AP1000
-  E(PROC_PID_RINGBUF,	"ringbuf",	S_IFREG|S_IRUGO|S_IWUSR),
-#endif
   E(PROC_PID_MAPS,	"maps",		S_IFREG|S_IRUGO),
   E(PROC_PID_MEM,	"mem",		S_IFREG|S_IRUSR|S_IWUSR),
   E(PROC_PID_CWD,	"cwd",		S_IFLNK|S_IRWXUGO),
@@ -869,11 +863,6 @@
 		case PROC_PID_CPU:
 			inode->i_op = &proc_info_inode_operations;
 			inode->u.proc_i.op.proc_read = proc_pid_cpu;
-			break;
-#endif
-#if CONFIG_AP1000
-		case PROC_PID_RINGBUF:
-			inode->i_op = &proc_ringbuf_inode_operations;
 			break;
 #endif
 		case PROC_PID_MEM:
diff -u --recursive --new-file v2.3.41/linux/fs/qnx4/bitmap.c linux/fs/qnx4/bitmap.c
--- v2.3.41/linux/fs/qnx4/bitmap.c	Tue Jan 11 22:31:43 2000
+++ linux/fs/qnx4/bitmap.c	Mon Jan 31 15:40:23 2000
@@ -76,14 +76,10 @@
 		count_bits(bh->b_data, size - total, &total_free);
 		brelse(bh);
 		total += QNX4_BLOCK_SIZE;
+		offset++;
 	}
 
 	return total_free;
-}
-
-unsigned long qnx4_count_free_inodes(struct super_block *sb)
-{
-	return qnx4_count_free_blocks(sb) * QNX4_INODES_PER_BLOCK;	/* FIXME */
 }
 
 #ifdef CONFIG_QNX4FS_RW
diff -u --recursive --new-file v2.3.41/linux/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- v2.3.41/linux/fs/qnx4/dir.c	Tue Jan 11 22:31:43 2000
+++ linux/fs/qnx4/dir.c	Mon Jan 31 15:40:23 2000
@@ -35,13 +35,13 @@
 	QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
 
 	while (filp->f_pos < inode->i_size) {
-		blknum = qnx4_block_map( inode, filp->f_pos / QNX4_BLOCK_SIZE );
+		blknum = qnx4_block_map( inode, filp->f_pos >> QNX4_BLOCK_SIZE_BITS );
 		bh = bread(inode->i_dev, blknum, QNX4_BLOCK_SIZE);
 		if(bh==NULL) {
 			printk(KERN_ERR "qnx4_readdir: bread failed (%ld)\n", blknum);
 			break;
 		}
-		ix = (filp->f_pos / QNX4_DIR_ENTRY_SIZE - (filp->f_pos / QNX4_BLOCK_SIZE) * QNX4_INODES_PER_BLOCK) % QNX4_INODES_PER_BLOCK;
+		ix = (int)(filp->f_pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK;
 		while (ix < QNX4_INODES_PER_BLOCK) {
 			offset = ix * QNX4_DIR_ENTRY_SIZE;
 			de = (struct qnx4_inode_entry *) (bh->b_data + offset);
diff -u --recursive --new-file v2.3.41/linux/fs/qnx4/inode.c linux/fs/qnx4/inode.c
--- v2.3.41/linux/fs/qnx4/inode.c	Tue Jan 11 22:31:43 2000
+++ linux/fs/qnx4/inode.c	Mon Jan 31 15:40:23 2000
@@ -275,13 +275,13 @@
 	struct statfs tmp;
 
 	memset(&tmp, 0, sizeof tmp);
-	tmp.f_type = sb->s_magic;
-	tmp.f_bsize = sb->s_blocksize;
-	tmp.f_blocks = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
-	tmp.f_bfree = qnx4_count_free_blocks(sb);
-	tmp.f_bavail = tmp.f_bfree;
-	tmp.f_files = 0x00;	/* change this !!! */
-	tmp.f_ffree = qnx4_count_free_inodes(sb);
+	tmp.f_type    = sb->s_magic;
+	tmp.f_bsize   = sb->s_blocksize;
+	tmp.f_blocks  = le32_to_cpu(sb->u.qnx4_sb.BitMap->di_size) * 8;
+	tmp.f_bfree   = qnx4_count_free_blocks(sb);
+	tmp.f_bavail  = tmp.f_bfree;
+	tmp.f_files   = -1;	/* we don't count files */
+	tmp.f_ffree   = -1;	/* inodes are allocated dynamically */
 	tmp.f_namelen = QNX4_NAME_MAX;
 
 	return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
diff -u --recursive --new-file v2.3.41/linux/fs/select.c linux/fs/select.c
--- v2.3.41/linux/fs/select.c	Fri Jan 28 15:09:09 2000
+++ linux/fs/select.c	Mon Jan 31 23:38:36 2000
@@ -414,11 +414,14 @@
 		wait = wait_table;
 	}
 
-	fds = (struct pollfd **)kmalloc(
-		(1 + (nfds - 1) / POLLFD_PER_PAGE) * sizeof(struct pollfd *),
-		GFP_KERNEL);
-	if (fds == NULL)
-		goto out;
+	fds = NULL;
+	if (nfds != 0) {
+		fds = (struct pollfd **)kmalloc(
+			(1 + (nfds - 1) / POLLFD_PER_PAGE) * sizeof(struct pollfd *),
+			GFP_KERNEL);
+		if (fds == NULL)
+			goto out;
+	}
 
 	nchunks = 0;
 	nleft = nfds;
@@ -467,7 +470,8 @@
 out_fds:
 	for (i=0; i < nchunks; i++)
 		free_page((unsigned long)(fds[i]));
-	kfree(fds);
+	if (nfds != 0)
+		kfree(fds);
 out:
 	if (wait)
 		free_wait(wait_table);
diff -u --recursive --new-file v2.3.41/linux/include/asm-alpha/checksum.h linux/include/asm-alpha/checksum.h
--- v2.3.41/linux/include/asm-alpha/checksum.h	Tue Apr 28 22:28:10 1998
+++ linux/include/asm-alpha/checksum.h	Mon Jan 31 23:41:14 2000
@@ -83,7 +83,7 @@
 #define _HAVE_ARCH_IPV6_CSUM
 extern unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
                                           struct in6_addr *daddr,
-                                          __u16 len,
+                                          __u32 len,
                                           unsigned short proto,
                                           unsigned int sum);
 
diff -u --recursive --new-file v2.3.41/linux/include/asm-arm/checksum.h linux/include/asm-arm/checksum.h
--- v2.3.41/linux/include/asm-arm/checksum.h	Fri Jan 21 18:19:17 2000
+++ linux/include/asm-arm/checksum.h	Mon Jan 31 23:41:14 2000
@@ -148,10 +148,10 @@
 		__u32 proto, unsigned int sum);
 
 extern __inline__ unsigned short int
-csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u16 len,
+csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u32 len,
 		unsigned short proto, unsigned int sum)
 {
-	return csum_fold(__csum_ipv6_magic(saddr, daddr, htonl((__u32)len),
+	return csum_fold(__csum_ipv6_magic(saddr, daddr, htonl(len),
 					   htonl(proto), sum));
 }
 #endif
diff -u --recursive --new-file v2.3.41/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h
--- v2.3.41/linux/include/asm-i386/checksum.h	Fri Jan  7 19:13:22 2000
+++ linux/include/asm-i386/checksum.h	Mon Jan 31 23:41:14 2000
@@ -154,7 +154,7 @@
 #define _HAVE_ARCH_IPV6_CSUM
 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
 						     struct in6_addr *daddr,
-						     __u16 len,
+						     __u32 len,
 						     unsigned short proto,
 						     unsigned int sum) 
 {
@@ -173,7 +173,7 @@
 		"
 		: "=&r" (sum)
 		: "r" (saddr), "r" (daddr), 
-		  "r"(htonl((__u32) (len))), "r"(htonl(proto)), "0"(sum));
+		  "r"(htonl(len)), "r"(htonl(proto)), "0"(sum));
 
 	return csum_fold(sum);
 }
diff -u --recursive --new-file v2.3.41/linux/include/asm-m68k/checksum.h linux/include/asm-m68k/checksum.h
--- v2.3.41/linux/include/asm-m68k/checksum.h	Wed Sep  2 09:39:18 1998
+++ linux/include/asm-m68k/checksum.h	Mon Jan 31 23:41:14 2000
@@ -123,7 +123,7 @@
 #define _HAVE_ARCH_IPV6_CSUM
 static __inline__ unsigned short int
 csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr,
-		__u16 len, unsigned short proto, unsigned int sum) 
+		__u32 len, unsigned short proto, unsigned int sum) 
 {
 	register unsigned long tmp;
 	__asm__("addl %2@,%0\n\t"
@@ -145,7 +145,7 @@
 		"clrl %1\n\t"
 		"addxl %1,%0"
 		: "=&d" (sum), "=&d" (tmp)
-		: "a" (saddr), "a" (daddr), "d" ((__u32) len + proto),
+		: "a" (saddr), "a" (daddr), "d" (len + proto),
 		  "0" (sum));
 
 	return csum_fold(sum);
diff -u --recursive --new-file v2.3.41/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h
--- v2.3.41/linux/include/asm-m68k/entry.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-m68k/entry.h	Mon Jan 31 10:32:53 2000
@@ -4,9 +4,6 @@
 #include <linux/config.h>
 #include <asm/setup.h>
 #include <asm/page.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
 
 /*
  * Stack layout in 'ret_from_exception':
@@ -69,7 +66,7 @@
  * regs a3-a6 and d6-d7 are preserved by C code
  * the kernel doesn't mess with usp unless it needs to
  */
-#ifndef CONFIG_KGDB
+
 /*
  * a -1 in the orig_d0 field signifies
  * that the stack frame is NOT for syscall
@@ -87,27 +84,6 @@
 	movel	%d0,%sp@-	| d0
 	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
 .endm
-#else
-/* Need to save the "missing" registers for kgdb...
- */
-.macro	save_all_int
-	clrl	%sp@-		| stk_adj
-	pea	-1:w		| orig d0
-	movel	%d0,%sp@-	| d0
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
-	moveml	%d6-%d7,kgdb_registers+GDBOFFA_D6
-	moveml	%a3-%a6,kgdb_registers+GDBOFFA_A3
-.endm
-
-.macro	save_all_sys
-	clrl	%sp@-		| stk_adj
-	movel	%d0,%sp@-	| orig d0
-	movel	%d0,%sp@-	| d0
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
-	moveml	%d6-%d7,kgdb_registers+GDBOFFA_D6
-	moveml	%a3-%a6,kgdb_registers+GDBOFFA_A3
-.endm
-#endif
 
 .macro	restore_all
 	moveml	%sp@+,%a0-%a1/%curptr/%d1-%d5
@@ -145,21 +121,11 @@
 #define PT_OFF_ORIG_D0	 0x24
 #define PT_OFF_FORMATVEC 0x32
 #define PT_OFF_SR	 0x2C
-#ifndef CONFIG_KGDB
 #define SAVE_ALL_INT				\
 	"clrl	%%sp@-;"    /* stk_adj */	\
 	"pea	-1:w;"	    /* orig d0 = -1 */	\
 	"movel	%%d0,%%sp@-;" /* d0 */		\
 	"moveml	%%d1-%%d5/%%a0-%%a2,%%sp@-"
-#else
-#define SAVE_ALL_INT				\
-	"clrl	%%sp@-\n\t" /* stk_adj */	\
-	"pea	-1:w\n\t"   /* orig d0 = -1 */	\
-	"movel	%%d0,%%sp@-\n\t" /* d0 */	\
-	"moveml	%%d1-%%d5/%%a0-%%a2,%%sp@-\n\t"	\
-	"moveml	%%d6-%%d7,kgdb_registers+"STR(GDBOFFA_D6)"\n\t" \
-	"moveml	%%a3-%%a6,kgdb_registers+"STR(GDBOFFA_A3)
-#endif
 #define GET_CURRENT(tmp) \
 	"movel	%%sp,"#tmp"\n\t" \
 	"andw	#-"STR(KTHREAD_SIZE)","#tmp"\n\t" \
diff -u --recursive --new-file v2.3.41/linux/include/asm-m68k/init.h linux/include/asm-m68k/init.h
--- v2.3.41/linux/include/asm-m68k/init.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-m68k/init.h	Mon Jan 31 23:43:51 2000
@@ -1,29 +1,11 @@
 #ifndef _M68K_INIT_H
 #define _M68K_INIT_H
 
-#include <linux/config.h>
-
-#ifndef CONFIG_KGDB
-
 #define __init __attribute__ ((__section__ (".text.init")))
 #define __initdata __attribute__ ((__section__ (".data.init")))
 /* For assembly routines */
 #define __INIT		.section	".text.init",#alloc,#execinstr
 #define __FINIT		.previous
 #define __INITDATA	.section	".data.init",#alloc,#write
-
-#else
-
-/* gdb doesn't like it all if the code for one source file isn't together in
- * the executable, so we must avoid the .init sections :-( */
-	
-#define __init
-#define __initdata
-/* For assembly routines */
-#define __INIT
-#define __FINIT
-#define __INITDATA
-
-#endif /* CONFIG_KGDB */
 
 #endif
diff -u --recursive --new-file v2.3.41/linux/include/asm-m68k/kgdb.h linux/include/asm-m68k/kgdb.h
--- v2.3.41/linux/include/asm-m68k/kgdb.h	Thu Jul 30 11:08:20 1998
+++ linux/include/asm-m68k/kgdb.h	Wed Dec 31 16:00:00 1969
@@ -1,83 +0,0 @@
-/*
- *  include/asm-m68k/kgdb.h
- *
- *  Copyright (C) 1996 Roman Hodek
- */
-
-#ifndef __ASM_M68k_KGDB_H
-#define __ASM_M68k_KGDB_H
-
-/*
- * Structure to save all register values in, already in the order gdb wants
- * it. Note that the upper half of the SR field is recycled for the FORMAT and
- * VECTOR fields. Hope that doesn't confuse gdb... That upper half is ignored
- * on exiting the stub, so gdb can modify it as it likes.
- */
-
-#define GDBREG_A6	14
-#define GDBREG_A7	15
-#define GDBREG_SP	15
-#define GDBREG_SR	16
-#define GDBREG_PC	17
-#define GDBREG_FP0	18
-#define GDBREG_FP7	25
-#define GDBREG_FPCR	26
-#define GDBREG_FPIAR 28
-
-#define GDBOFFA_D6	(6*4)
-#define GDBOFFA_A3	(11*4)
-
-#define NUMREGSBYTES	180
-
-#ifndef __ASSEMBLY__
-
-struct gdb_regs {
-    long		   regs[16];		/* d0-a7 */
-    unsigned	   format :  4; 	/* frame format specifier */
-    unsigned	   vector : 12; 	/* vector offset */
-    unsigned short sr;				/* status register */
-    unsigned long  pc;				/* program counter */
-	unsigned long  fpregs[8*3];		/* fp0-fp7 */
-	unsigned long  fpcntl[3];		/* fpcr, fpsr, fpiar */
-};
-
-extern struct gdb_regs kgdb_registers;
-extern void kgdb_init( void );
-struct frame;
-extern asmlinkage void enter_kgdb( struct pt_regs *fp );
-
-extern int kgdb_initialized;
-
-/*
- * This function will generate a breakpoint exception.  It is used at the
- * beginning of a program to sync up with a debugger and can be used
- * otherwise as a quick means to stop program execution and "break" into
- * the debugger.
- */
-extern inline void breakpoint( void )
-{
-	if (!kgdb_initialized)
-		/* if kgdb not inited, do nothing */
-		return;
-	
-	/* breakpoint instruction is TRAP #15 */
-	__asm__ __volatile__ ( "trap #15" );
-}
-
-/*
- * This function will report a SIGABORT to gdb.
- */
-extern inline void kgdb_abort( void )
-{
-	if (!kgdb_initialized)
-		/* if kgdb not inited, do nothing */
-		return;
-	
-	/* TRAP #14 is reported as SIGABORT */
-	__asm__ __volatile__ ( "trap #14" );
-}
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __ASM_M68k_KGDB_H */
-
diff -u --recursive --new-file v2.3.41/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.3.41/linux/include/asm-m68k/semaphore.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-m68k/semaphore.h	Mon Jan 31 10:32:53 2000
@@ -1,6 +1,8 @@
 #ifndef _M68K_SEMAPHORE_H
 #define _M68K_SEMAPHORE_H
 
+#define RW_LOCK_BIAS		 0x01000000
+
 #ifndef __ASSEMBLY__
 
 #include <linux/linkage.h>
@@ -205,11 +207,38 @@
 	atomic_t		writers;
 #endif
 };
-#endif /* __ASSEMBLY__ */
 
-#define RW_LOCK_BIAS		 0x01000000
+#if WAITQUEUE_DEBUG
+#define __RWSEM_DEBUG_INIT	, ATOMIC_INIT(0), ATOMIC_INIT(0)
+#else
+#define __RWSEM_DEBUG_INIT	/* */
+#endif
 
-#ifndef __ASSEMBLY__
+#define __RWSEM_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
+	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
+
+extern inline void init_rwsem(struct rw_semaphore *sem)
+{
+	atomic_set(&sem->count, RW_LOCK_BIAS);
+	sem->read_bias_granted = 0;
+	sem->write_bias_granted = 0;
+	init_waitqueue_head(&sem->wait);
+	init_waitqueue_head(&sem->write_bias_wait);
+#if WAITQUEUE_DEBUG
+	sem->__magic = (long)&sem->__magic;
+	atomic_set(&sem->readers, 0);
+	atomic_set(&sem->writers, 0);
+#endif
+}
 
 extern inline void down_read(struct rw_semaphore *sem)
 {
diff -u --recursive --new-file v2.3.41/linux/include/asm-mips/checksum.h linux/include/asm-mips/checksum.h
--- v2.3.41/linux/include/asm-mips/checksum.h	Tue Oct 20 13:52:53 1998
+++ linux/include/asm-mips/checksum.h	Mon Jan 31 23:41:14 2000
@@ -186,7 +186,7 @@
 #define _HAVE_ARCH_IPV6_CSUM
 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
 						     struct in6_addr *daddr,
-						     __u16 len,
+						     __u32 len,
 						     unsigned short proto,
 						     unsigned int sum) 
 {
@@ -244,7 +244,7 @@
 		  "=r" (proto)
 		: "r" (saddr),
 		  "r" (daddr),
-		  "0" (htonl((__u32) (len))),
+		  "0" (htonl(len)),
 		  "1" (htonl(proto)),
 		  "r"(sum)
 		: "$1");
diff -u --recursive --new-file v2.3.41/linux/include/asm-sh/checksum.h linux/include/asm-sh/checksum.h
--- v2.3.41/linux/include/asm-sh/checksum.h	Fri Oct 22 13:21:54 1999
+++ linux/include/asm-sh/checksum.h	Mon Jan 31 23:41:14 2000
@@ -189,7 +189,7 @@
 #define _HAVE_ARCH_IPV6_CSUM
 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
 						     struct in6_addr *daddr,
-						     __u16 len,
+						     __u32 len,
 						     unsigned short proto,
 						     unsigned int sum) 
 {
@@ -217,7 +217,7 @@
 		"add	%1,%0\n"
 		: "=r" (sum), "=&r" (__dummy)
 		: "r" (saddr), "r" (daddr), 
-		  "r" (htonl((__u32) (len))), "r" (htonl(proto)), "0" (sum));
+		  "r" (htonl(len)), "r" (htonl(proto)), "0" (sum));
 
 	return csum_fold(sum);
 }
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/ap1000/DdvReqTable.h linux/include/asm-sparc/ap1000/DdvReqTable.h
--- v2.3.41/linux/include/asm-sparc/ap1000/DdvReqTable.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/ap1000/DdvReqTable.h	Wed Dec 31 16:00:00 1969
@@ -1,107 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/*
- *	Request table size
- */
-
-#define	TABLE_SIZE	200
-
-/*
- *	Indirect memory address table size
- */
-
-#define	MTABLE_SIZE	1000
-
-static inline int INC_T(int a)
-{
-	return (++a == TABLE_SIZE?0:a);
-}
-
-static inline int INC_ML(int a)
-{
-	return (++a == MTABLE_SIZE?0:a);
-}
-
-/*
- *	Status of requiest table
- */
-
-#define	DDV_ERROR_RETURN	0
-#define	DDV_NORMAL_RETURN	1
-#define	DDV_REQ_FREE		2
-#define DDV_DISKREAD_REQ	3
-#define	DDV_DISKWRITE_REQ	4
-#define DDV_RAWREAD_REQ		5
-#define	DDV_RAWWRITE_REQ	6
-#define DDV_CACHEPOSTALL_REQ    11
-#define DDV_CACHEFLUSHALL_REQ    12
-#define DDV_CAPACITY_REQ        13
-
-/*
- *      Specify type of interrupt (set by opiu in PBUF1)
- */
-
-#define DDV_PRINTK_INTR  1
-#define DDV_MLIST_INTR   2
-#define DDV_READY_INTR   3
-#define DDV_REQCOMP_INTR 4 
-
-struct  RequestInformation {
-	volatile int	status;
-	int rtn;
-	unsigned bnum;
-	int argv[8];
-};
-
-struct DiskInfo {
-  u_long blocks;
-  u_long blk_size;
-  int pad[8];
-  unsigned ptrs[4];
-};
-
-struct RequestTable{
-  volatile unsigned cell_pointer;	/* Cell requiest pointer */
-  volatile unsigned ddv_pointer;	/* DDV operation pointer */
-  struct  RequestInformation async_info[TABLE_SIZE];
-  volatile unsigned start_mtable;
-  volatile unsigned end_mtable;
-  unsigned mtable[MTABLE_SIZE];
-};
-
-#define PRINT_BUFS 32
-
-struct OPrintBuf {
-  char *fmt;
-  int args[6];
-};
-
-struct OPrintBufArray {
-  volatile unsigned option_counter;
-  volatile unsigned cell_counter;
-  struct OPrintBuf bufs[PRINT_BUFS];  
-};
-
-#define ALIGN_SIZE 16
-#define ALIGN_BUFS 128
-#define ALIGN_BUF_SIZE 1024
-
-struct AlignBuf {
-  char *dest;
-  unsigned size;
-  int offset;
-  char buf[ALIGN_BUF_SIZE+2*ALIGN_SIZE];
-};
-
-struct OAlignBufArray {
-  volatile unsigned option_counter;
-  volatile unsigned cell_counter;
-  struct AlignBuf bufs[ALIGN_BUFS];
-};
-
-
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/ap1000/apbif.h linux/include/asm-sparc/ap1000/apbif.h
--- v2.3.41/linux/include/asm-sparc/ap1000/apbif.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/ap1000/apbif.h	Wed Dec 31 16:00:00 1969
@@ -1,205 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-
-/*
-**	BIF data registers (system mode)
-*/
-#define BIF_DATA 	(BIF+0x0000)	/* BIF send and receive data registe	*/
-#define BIF_EDATA  	(BIF+0x0004)	/* BIF end data register 				*/
-/*
-**	BIF data registers (user mode) 
-*/
-#define UBIF_DATA 	(UBIF+0x0000)	/* BIF send and receive data registe	*/
-#define UBIF_EDATA  (UBIF+0x0004)	/* BIF end data register 				*/
-
-/*
-**	BIF scatter and gather parameter register (system mode) 
-*/
-#define BIF_X0SK 	(BIF+0x0010)	/* initial X-skip register 			*/
-#define BIF_XSK 	(BIF+0x0014)	/* X-skip register 					*/
-#define BIF_XSZ 	(BIF+0x0018)	/* X-size register 					*/
-
-#define BIF_Y0SK 	(BIF+0x001c)	/* initial Y-skip register 			*/
-#define BIF_YSK 	(BIF+0x0020)	/* Y-skip register 					*/
-#define BIF_YSZ 	(BIF+0x0024)	/* Y-size register 					*/
-
-#define BIF_CX0SK 	(BIF+0x0028)	/* initial counter of X-skip 		*/
-#define BIF_CXSK 	(BIF+0x002c)	/* X-skip counter 					*/
-#define BIF_CXSZ 	(BIF+0x0030)	/* X-size counter 					*/
-
-#define BIF_CY0SK 	(BIF+0x0034)	/* initial counter of Y-skip 		*/
-#define BIF_CYSK 	(BIF+0x0038)	/* Y-skip counter 					*/
-#define BIF_CYSZ 	(BIF+0x003c)	/* Y-size counter 					*/
-
-#define BIF_TTL 	(BIF+0x0040)	/* number of data transfer register */
-#define BIF_CTTL 	(BIF+0x0044)	/* number of data transfer counter	*/
-
-/*
-**	BIF scatter and gather parameter register (user mode) 
-*/
-#define UBIF_X0SK 	(UBIF+0x0010)	/* initial X-skip register 			*/
-#define UBIF_XSK 	(UBIF+0x0014)	/* X-skip register 					*/
-#define UBIF_XSZ 	(UBIF+0x0018)	/* X-size register 					*/
-
-#define UBIF_Y0SK 	(UBIF+0x001c)	/* initial Y-skip register 			*/
-#define UBIF_YSK 	(UBIF+0x0020)	/* Y-skip register 					*/
-#define UBIF_YSZ 	(UBIF+0x0024)	/* Y-size register 					*/
-
-#define UBIF_CX0SK 	(UBIF+0x0028)	/* initial counter of X-skip 		*/
-#define UBIF_CXSK 	(UBIF+0x002c)	/* X-skip counter 					*/
-#define UBIF_CXSZ 	(UBIF+0x0030)	/* X-size counter 					*/
-
-#define UBIF_CY0SK 	(UBIF+0x0034)	/* initial counter of Y-skip 		*/
-#define UBIF_CYSK 	(UBIF+0x0038)	/* Y-skip counter 					*/
-#define UBIF_CYSZ 	(UBIF+0x003c)	/* Y-size counter 					*/
-
-#define UBIF_TTL 	(UBIF+0x0040)	/* number of data transfer register */
-#define UBIF_CTTL 	(UBIF+0x0044)	/* number of data transfer counter	*/
-
-/*
-**	BIF control registers (system mode)
-*/
-#define BIF_CIDR0 	(BIF+0x0048)	/* cell-id register 0 					*/
-#define BIF_CIDR1 	(BIF+0x004c)	/* cell-id register 1 (for cell mode) 	*/
-#define BIF_CIDR2 	(BIF+0x0050)	/* cell-id register 2 					*/
-#define BIF_CIDR3 	(BIF+0x0054)	/* cell-id register 3 					*/
-#define BIF_HEADER 	(BIF+0x0058)	/* header register 						*/
-#define BIF_INTR 	(BIF+0x006c)	/* BIF interrupt control register 		*/
-#define BIF_SDCSR 	(BIF+0x0070)	/* BIF data control set register 		*/
-#define BIF_RDCSR 	(BIF+0x0074)	/* BIF data control reset reregister	*/
-#define BIF_MHOCR 	(BIF+0x0078)	/* BIF extentional control reregister 	*/
-
-/*
-**	BIF control registers (user mode)
-*/
-#define UBIF_CIDR0 	(UBIF+0x0048)	/* cell-id register 0 					*/
-#define UBIF_CIDR1 	(UBIF+0x004c)	/* cell-id register 1 (for cell mode) 	*/
-#define UBIF_CIDR2 	(UBIF+0x0050)	/* cell-id register 2 					*/
-#define UBIF_CIDR3 	(UBIF+0x0054)	/* cell-id register 3 					*/
-#define UBIF_HEADER (UBIF+0x0058)	/* header register 						*/
-#define UBIF_INTR 	(UBIF+0x006c)	/* BIF interrupt control register 		*/
-#define UBIF_SDCSR 	(UBIF+0x0070)	/* BIF data control set register 		*/
-#define UBIF_RDCSR 	(UBIF+0x0074)	/* BIF data control reset reregister	*/
-#define UBIF_MHOCR 	(UBIF+0x0078)	/* BIF extentional control reregister 	*/
-
-/*
-** bit assignment 
-*/
-#define BIF_HEADER_ID	 0xffff0000	/* cell-id   		*/
-#define BIF_HEADER_BR	 0x00008000	/* broad bit 		*/
-#define BIF_HEADER_IS	 0x00006000	/* ID select		*/
-#define BIF_HEADER_IS_00 0x00000000 
-#define BIF_HEADER_IS_01 0x00002000 
-#define BIF_HEADER_IS_10 0x00004000 
-#define BIF_HEADER_IS_11 0x00006000 
-#define BIF_HEADER_IN	 0x00001000	/* interrupt bit	*/
-#define BIF_HEADER_LS	 0x00000800	/* line send		*/
-#define BIF_HEADER_SC	 0x00000400	/* scatter bit 		*/
-#define BIF_HEADER_HS	 0x00000200	/* header strip		*/
-#define BIF_HEADER_RS	 0x00000100	/* bus release 		*/
-
-#define BIF_HEADER_ID_SHIFT 16
-
-#define BIF_INTR_GS		0x00020000	/* grant interrupt select 		*/
-#define BIF_INTR_GM		0x00010000	/* grant interrupt mask			*/
-#define BIF_INTR_GI		0x00008000	/* grant interrupt request		*/
-#define BIF_INTR_HS		0x00004000	/* header interrupt select		*/
-#define BIF_INTR_HM		0x00002000	/* header interrupt mask		*/
-#define BIF_INTR_HI		0x00001000	/* header interrupt request		*/
-#define BIF_INTR_SS		0x00000800	/* send interrupt select		*/
-#define BIF_INTR_SM		0x00000400	/* send interrupt mask			*/
-#define BIF_INTR_SI		0x00000200	/* send interrupt request		*/
-#define BIF_INTR_RS		0x00000100	/* receive interrupt select		*/
-#define BIF_INTR_RM		0x00000080	/* receive interrupt mask		*/
-#define BIF_INTR_RI		0x00000040	/* receive interrupt request	*/
-#define BIF_INTR_ES		0x00000020	/* error interrupt select 		*/
-#define BIF_INTR_EM		0x00000010	/* error interrupt mask 		*/
-#define BIF_INTR_EI		0x00000008	/* error interrupt request 		*/
-#define BIF_INTR_AS		0x00000004	/* attention interrupt select 	*/
-#define BIF_INTR_AM		0x00000002	/* attention interrupt mask 	*/
-#define BIF_INTR_AI		0x00000001	/* attention interrupt request  */
-
-#define BIF_SDCSR_ER    0x7fffc000  /* error  detected by BIF */
-#define BIF_SDCSR_PE	0x80000000	/* detect parity error in sync			*/
-#define BIF_SDCSR_SP	0x40000000	/* parity error in sync					*/
-#define BIF_SDCSR_LP	0x20000000	/* L-bus parity error					*/
-#define BIF_SDCSR_LR	0x10000000	/* */
-#define BIF_SDCSR_LW	0x08000000	/* */
-#define BIF_SDCSR_AL	0x04000000	/* specify end bit except of end data	*/
-#define BIF_SDCSR_SS	0x02000000	/* request bit but masked by slow sync	*/
-#define BIF_SDCSR_SC	0x01000000	/* clear bit but masked by slow sync	*/
-#define BIF_SDCSR_SY	0x00800000	/* set bit but masked by slow status	*/
-#define BIF_SDCSR_FS	0x00400000	/* request bit but masked by fast sync	*/
-#define BIF_SDCSR_FC	0x00200000	/* clear bit but masked by fast sync	*/
-#define BIF_SDCSR_FY	0x00100000	/* set bit but masked by fast status	*/
-#define BIF_SDCSR_CP	0x00080000	/* parity error in commnad bus			*/
-#define BIF_SDCSR_FP	0x00040000	/* execute scatter or gather but FN=0	*/
-#define BIF_SDCSR_PS	0x00020000	/* header receive error 				*/
-#define BIF_SDCSR_RA	0x00010000	/* change scatter,gather parameter		*/
-#define BIF_SDCSR_PA	0x00008000	/* check if send or receive error		*/
-#define BIF_SDCSR_DL	0x00004000	/* lost data							*/
-#define BIF_SDCSR_BB	0x00002000	/* check if some BIF use command bus	*/
-#define BIF_SDCSR_BG	0x00001000	/* check if command bus got				*/
-#define BIF_SDCSR_BR	0x00000800	/* request command bus					*/
-#define BIF_SDCSR_CN	0x00000400	/* release BIF from command bus			*/
-#define BIF_SDCSR_FN	0x00000200	/* scatter gather enable				*/
-#define BIF_SDCSR_EB	0x00000100	/* send data that have end bit			*/
-#define BIF_SDCSR_TB	0x000000E0	/* data in send FIFO					*/
-#define BIF_SDCSR_TB4	0x00000080
-#define BIF_SDCSR_TB2	0x00000040
-#define BIF_SDCSR_TB1	0x00000020
-#define BIF_SDCSR_RB	0x0000001c	/* data in receive FIFO					*/
-#define BIF_SDCSR_RB4	0x00000010
-#define BIF_SDCSR_RB2	0x00000008	
-#define BIF_SDCSR_RB1	0x00000004	
-#define BIF_SDCSR_DE	0x00000002	/* DMA interface enable bitr			*/
-#define BIF_SDCSR_DR	0x00000001	/* data transfer direction				*/
-
-#define BIF_RDCSR_ER    BIF_SDCSR_ER    /* error  detected by BIF */
-#define BIF_RDCSR_PE	BIF_SDCSR_PE	/* detect parity error in sync		*/
-#define BIF_RDCSR_SP	BIF_SDCSR_SP	/* parity error in sync	  */
-#define BIF_RDCSR_LP	BIF_SDCSR_LP	/* L-bus parity error	  */
-#define BIF_RDCSR_LR	BIF_SDCSR_LR	/* */
-#define BIF_RDCSR_LW	BIF_SDCSR_LW	/* */
-#define BIF_RDCSR_AL	BIF_SDCSR_AL	/* specify end bit except of end data */
-#define BIF_RDCSR_SS	BIF_SDCSR_SS	/* request bit but masked by slow sync	*/
-#define BIF_RDCSR_SC	BIF_SDCSR_SC	/* clear bit but masked by slow sync  */
-#define BIF_RDCSR_SY	BIF_SDCSR_SY	/* set bit but masked by slow status  */
-#define BIF_RDCSR_FS	BIF_SDCSR_FS	/* request bit but masked by fast sync*/
-#define BIF_RDCSR_FC	BIF_SDCSR_FC	/* clear bit but masked by fast sync  */
-#define BIF_RDCSR_FY	BIF_SDCSR_FY	/* set bit but masked by fast status  */
-#define BIF_RDCSR_CP	BIF_SDCSR_CP	/* parity error in commnad bus        */
-#define BIF_RDCSR_FP	BIF_SDCSR_FP	/* execute scatter or gather but FN=0 */
-#define BIF_RDCSR_PS	BIF_SDCSR_PS	/* header receive error 			*/
-#define BIF_RDCSR_RA	BIF_SDCSR_RA	/* change scatter,gather parameter		*/
-#define BIF_RDCSR_DL	BIF_SDCSR_DL	/* lost data					*/
-#define BIF_RDCSR_PA	BIF_SDCSR_PA	/* check if send or receive error	  */
-#define BIF_RDCSR_BB	BIF_SDCSR_BB	/* check if some BIF use command bus  */
-#define BIF_RDCSR_BG	BIF_SDCSR_BG	/* check if command bus got		*/
-#define BIF_RDCSR_BR	BIF_SDCSR_BR	/* request command bus			*/
-#define BIF_RDCSR_CN	BIF_SDCSR_CN	/* release BIF from command bus	*/
-#define BIF_RDCSR_EB	BIF_SDCSR_EB	/* send data that have end bit	*/
-#define BIF_RDCSR_TB	BIF_SDCSR_TB	/* data in send FIFO			*/
-#define BIF_RDCSR_RB	BIF_SDCSR_RB	/* data in receive FIFO			*/
-#define BIF_RDCSR_DE	BIF_SDCSR_DE	/* DMA interface enable bitr	*/
-#define BIF_RDCSR_DR	BIF_SDCSR_DR	/* data transfer direction		*/
-#define BIF_RDCSR_FN	BIF_SDCSR_FN	/* scatter gather enable		*/
-
-#define BIF_MHOCR_RS	0x00000800		/* bif reset						*/
-#define BIF_MHOCR_RC	0x00000400		/* commnad bus circuit reset		*/
-#define BIF_MHOCR_RI	0x00000200		/* remove input buffer data			*/
-#define BIF_MHOCR_RO	0x00000100		/* remove output buffer data		*/
-#define BIF_MHOCR_BA	0x00000008		/* command bus arbitlater reset		*/
-#define BIF_MHOCR_MD	0x00000006		/* command bus mode					*/
-#define BIF_MHOCR_AT	0x00000001		/* command bus attention signal		*/
-
-#define BIF_MHOCR_MD_NORMAL	0x00000006	/* command bus mode [normal]		*/
-#define BIF_MHOCR_MD_BUSWGR	0x00000004	/* command bus mode [bus gather]	*/
-#define BIF_MHOCR_MD_SETCID	0x00000002	/* command bus mode [set cid]		*/
-
-
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/ap1000/aplib.h linux/include/asm-sparc/ap1000/aplib.h
--- v2.3.41/linux/include/asm-sparc/ap1000/aplib.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/ap1000/aplib.h	Wed Dec 31 16:00:00 1969
@@ -1,119 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-
-/* aplib kernel interface definition */
-
-#ifndef _APLIB_H_
-#define _APLIB_H_
-
-struct aplib_struct {
-	unsigned *ringbuf;
-	unsigned write_pointer, read_pointer; /* in words */
-	unsigned ringbuf_size; /* in words */
-	unsigned rbuf_counter; /* read messages */
-	unsigned rbuf_flag1, rbuf_flag2; /* received messages */
-	unsigned *physical_cid; /* logical to physical mapping */
-	unsigned *rel_cid;      /* logical to relative (RTC) mapping */
-	unsigned numcells; /* number of logical cells */
-	unsigned numcells_x; /* number of logical cells in x direction */
-	unsigned numcells_y; /* number of logical cells in y direction */
-	unsigned cid, tid;      /* this cells logical cell ID and task ID */
-	unsigned cidx, cidy;    /* logical cell id in x and y direction */
-	unsigned ack_flag, ack_request;
-	unsigned ok_x, ok_y, ok_xy; /* whether hardware x, y and xy sends are allowed */
-};
-
-
-/*
- * the system ringbuffer structure
- * this is also the old way that tasks accessed the MSC hardware
- */
-struct ringbuf_struct {
-	void *ringbuf; /* pointer to the ringbuf */
-	void *shared; /* pointer to the shared page */
-	int order; /* arg to __get_free_pages */
-	unsigned write_ptr; /* write pointer into the ringbuf */
-	unsigned vaddr; /* base virtual address of ringbuf for task */
-	unsigned frag_count; /* how many words in the frag queue */
-	unsigned frag_len; /* how many words expected in the frag queue */
-	unsigned sq_fragment[16]; /* if the task switches part way through
-				     an op then shove the partial op here */
-};
-
-
-#define APLIB_INIT    1
-#define APLIB_SYNC    2
-#define APLIB_GET     3
-#define APLIB_PUT     4
-#define APLIB_SEND    5
-#define APLIB_PROBE   6
-#define APLIB_POLL    7
-#define APLIB_XSEND   8
-#define APLIB_YSEND   9
-#define APLIB_XYSEND 10
-#define APLIB_XPUT   11
-#define APLIB_YPUT   12
-#define APLIB_XYPUT  13
-
-
-/* message kinds */
-#define RBUF_SYSTEM  0
-#define RBUF_SEND    1
-#define RBUF_X_BRD   2
-#define RBUF_Y_BRD   3
-#define RBUF_XY_BRD  4
-#define RBUF_RPC     5
-#define RBUF_GET     6
-#define RBUF_MPI     7
-#define RBUF_BIGSEND 8
-#define RBUF_SEEN   0xE
-#define RBUF_READ   0xF
-
-#define APLIB_PAGE_BASE 0xd0000000
-#define APLIB_PAGE_LEN  8192
-
-struct aplib_init {
-	unsigned numcells, cid;
-	unsigned numcells_x, numcells_y;
-	unsigned *phys_cells; /* physical cell list */
-	unsigned *ringbuffer;  /* pointer to user supplied ring buffer */
-	unsigned ringbuf_size; /* in words */
-};
-
-
-struct aplib_putget {
-	unsigned cid;
-	unsigned *src_addr, *dest_addr;
-	unsigned size; /* in words */
-	unsigned *dest_flag, *src_flag;
-	unsigned ack;
-};
-
-
-struct aplib_send {
-	/* the ordering here is actually quite important - the parts to be
-	   read by the bigrecv function must be in the first 24 bytes */
-	unsigned src_addr;
-	unsigned size;
-	unsigned info1, info2;
-	unsigned flag_addr;
-	volatile unsigned flag;
-	unsigned type;
-	unsigned tag;
-	unsigned cid;
-};
-
-#ifdef __KERNEL__
-#define MAX_PUT_SIZE (1024*1024 - 1) /* in words */
-#define SMALL_SEND_THRESHOLD 128
-
-
-#endif
-
-#endif /* _APLIB_H_ */
-
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/ap1000/apreg.h linux/include/asm-sparc/ap1000/apreg.h
--- v2.3.41/linux/include/asm-sparc/ap1000/apreg.h	Tue Sep  7 12:14:07 1999
+++ linux/include/asm-sparc/ap1000/apreg.h	Wed Dec 31 16:00:00 1969
@@ -1,619 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* ap1000 register definitions needed for Linux/AP+ */
-
-#ifndef _AP1000_APREG_H
-#define _AP1000_APREG_H
-#include <asm/page.h>
-#include <asm/ap1000/apservice.h>
-#include <asm/ap1000/apbif.h>
-#include <linux/threads.h>
-
-/*
- * Macros for accessing I/O registers.
- */
-#define BIF_IN(reg)	(*(volatile unsigned *)(reg))
-#define BIF_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
-#define DMA_IN(reg)	(*(volatile unsigned *)(reg))
-#define DMA_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
-#define MC_IN(reg)	(*(volatile unsigned *)(reg))
-#define MC_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
-#define MSC_IN(reg)	(*(volatile unsigned *)(reg))
-#define MSC_OUT(reg,v)	(*(volatile unsigned *)(reg) = (v))
-#define MSC_IO(reg)	(*(volatile unsigned *)(reg))
-#define RTC_IO(reg)	(*(volatile unsigned *)(reg))
-#define MC_IO(reg)	(*(volatile unsigned *)(reg))
-#define OPT_IO(reg)	(*(volatile unsigned *)(reg))
-
-/*
- * B-net interface register definitions.
- */
-#define BIF 	0xfff30000	
-#define BIF_CIDR1 	(BIF+0x004c)	/* cell-id register 1 (for cell mode)*/
-#define BIF_SDCSR 	(BIF+0x0070)	/* BIF data control set register  */
-#define BIF_DATA 	(BIF+0x0000)	/* BIF send and receive data registe	*/
-#define BIF_EDATA  	(BIF+0x0004)	/* BIF end data register 		*/
-#define BIF_INTR 	(BIF+0x006c)	/* BIF interrupt control register 	*/
-
-#define SSTT_SET	(BIF+0xe0)	/* set SSTT 			*/
-#define SSTT_CLR	(BIF+0xe4)	/* clear SSTT 			*/
-#define SSTT_SMSK	(BIF+0xe8)	/* set SSTT mask		*/
-#define SSTT_CMSK	(BIF+0xec)	/* clear SSTT mask		*/
-#define SSTT_SMD	(BIF+0xf0)	/* set SSYN & SSTT mode		*/
-#define SSTT_CMD	(BIF+0xf4)	/* clear SSYN & SSTT mode	*/
-
-/*
-** FSTT registers
-*/
-#define FSTT	BIF	/*	FSTT only system mode	*/
-#define FSTT_SET	(FSTT+0xa0)	/* set FSTT 			  */
-#define FSTT_CLR	(FSTT+0xa4)	/* clear FSTT 			  */
-#define FSTT_SMSK	(FSTT+0xa8)	/* set FSTT mask		  */
-#define FSTT_CMSK	(FSTT+0xac)	/* clear FSTT mask		  */
-#define FSTT_SMD	(FSTT+0xb0)	/* set FSYN & FSTT mode		  */
-#define FSTT_CMD	(FSTT+0xb4)	/* clear FSYN & FSTT mode	  */
-#define FSTT_TIM	(FSTT+0xb8)	/* status timer			  */
-
-
-#define BIF_SDCSR_RB	0x0000001c	/* data in receive FIFO		  */
-#define BIF_SDCSR_EB	0x00000100	/* send data that have end bit	  */
-#define BIF_SDCSR_BG	0x00001000	/* check if command bus got	  */
-#define BIF_SDCSR_BR	0x00000800	/* request command bus		  */
-#define BIF_SDCSR_TB	0x000000E0	/* data in send FIFO		  */
-#define BIF_SDCSR_PE	0x80000000	/* detect parity error in sync	       	*/
-#define BIF_SDCSR_BB    0x00002000      /* check if some BIF use command bus    */
-
-#define BIF_SDCSR_RB_SHIFT 2
-#define BIF_SDCSR_TB_SHIFT 5
-
-#define BIF_INTR_GET_SH       15         /* get bus interrupt */
-#define BIF_INTR_HEADER_SH    12         /* header interrupt */
-#define BIF_INTR_SEND_SH      9          /* send interrupt */
-#define BIF_INTR_RECV_SH      6          /* receive interrupt */
-#define BIF_INTR_ERR_SH       3          /* error interrupt */
-#define BIF_INTR_ATTN_SH      0          /* attention interrupt */
-
-
-#define BIF_HEADER_HS	0x00000200	/* header strip		*/
-#define BIF_HEADER_RS	0x00000100	/* bus release 		*/
-#define BIF_HEADER_IN	0x00001000	/* interrupt bit	*/
-#define BIF_HEADER_BR   0x00008000    /* broad bit    */
-#define BIF_INTR_HS		0x00004000	/* header interrupt select  */
-#define HOST_CID      0x1000
-#define MAKE_HEADER(cid) (BIF_HEADER_IN | \
-			  ((cid)==-1?BIF_HEADER_BR:((cid)<<16) | (1<<13)))
-
-#define BIF_RDCSR 	(BIF+0x0074)	/* BIF data control reset reregister */
-
-/*
- * Interrupt levels for AP+ devices
- */
-#define APBIFGET_IRQ	1		/* have acquired B-net */
-#define APOPT0_IRQ	2		/* option interrupt level 0 */
-#define APSYNC_IRQ	3		/* sync (S-net) interrupt */
-#define APDMA_IRQ	4		/* DMA complete interrupt */
-#define APRTC_IRQ	5		/* RTC data transfer interrupt */
-#define APIPORT_IRQ	6		/* Interrupt port interrupt */
-#define APOPT1_IRQ	7		/* option interrupt level 1 */
-#define APBIF_IRQ	8		/* B-net interface interrupt */
-#define APMAS_IRQ	9		/* Send/Recv mem acc. seq. intr */
-#define APTIM1_IRQ	10		/* Timer 1 interrupt */
-#define APMSC_IRQ	11		/* MSC+ ring buf/queue spill etc. */
-#define APLBUS_IRQ	12		/* LBUS error interrupt */
-#define APATTN_IRQ	13		/* Attention interrupt */
-#define APTIM0_IRQ	14		/* Timer 0 interrupt */
-#define APMEM_IRQ	15		/* Memory error interrupt */
-
-/*
- * LBUS DMA controller register definitions
- */
-#define DMA     0xfff00000 /* dma controller address */
-#define DMA3    (DMA+0xc0) /* DMA channel 3 */
-#define DMA_DMST    0x04
-#define DMA_MADDR   0x10
-#define DMA_HSKIP   0x08
-#define DMA_HCNT    0x0a
-#define DMA_VSKIP   0x0c
-#define DMA_VCNT    0x0e
-#define DMA_DCMD    0x00
-#define DMA_HDRP    0x28
-#define DMA_DSIZE   0x02
-#define DMA_CSIZE   0x06
-#define DMA_VCNT    0x0e
-
-#define DMA_BIF_BCMD	(DMA+0x120)	/* BIF receive command register	*/
-#define	DMA_BIF_BRST	(DMA+0x124)	/* BIF receive status register */
-#define	DMA_BCMD_SA		0x40000000	/* software abort   */
-#define	DMA_DMST_AC		0x80000000	/* channel active   */
-#define DMA_DMST_RST		0xffe40000  /* reset bits and reqs */
-#define	DMA_DCMD_ST		0x80000000	/* start operation    */
-#define	DMA_DCMD_TYP_AUTO	0x30000000	/* 11: auto  */
-
-#define	DMA_DCMD_TD_MD		0x04000000	/* transfer mem->dev */
-#define	DMA_DCMD_TD_DM		0x00000000	/* transfer direction dev->mem*/
-
-#define DMA_CH2    (DMA+0x80)	/* DMA channel 2	*/
-#define DMA_CH3    (DMA+0xc0)	/* DMA channel 3	*/
-#define DMA2_DMST  (DMA_CH2+0x04)		/* DMA2 status register	  */
-#define DMA3_DMST  (DMA_CH3+0x04)		/* DMA3 status register	  */
-#define DMA2_DCMD   (DMA_CH2+0x00)		/* DMA2 command register  */
-
-#define DMA_INTR_NORMAL_SH     19               /* normal DMA interrupt */
-#define DMA_INTR_ERROR_SH      16               /* error DMA interrupt */
-
-#define	DMA_DCMD_SA		0x40000000	/* software abort     */
-
-
-#define DMA_MAX_TRANS_SIZE		(0xffff<<2)
-#define DMA_TRANS_BLOCK_SIZE	(64<<2)
-
-#define WORD_SIZE 4
-#define B2W(x)    (((x) + WORD_SIZE - 1) / WORD_SIZE)
-#define W2B(x)    ((x) * WORD_SIZE)
-
-#define DMA_GEN		0xfff00180		/* DMA general control reg */
-
-/* AP1000+ Message Controller (MSC+) */
-
-#define MSC_BASE0 0xfa008000
-
-#define MSC_SQCTRL	(MSC_BASE0 + 0x0)	/* Send Queue control */
-
-/* bits in MSC_SQCTRL */
-#define MSC_SQC_STABLE	0x400			/* Send Queue stable */
-#define MSC_SQC_MODE	0x300			/* Send Queue mode: */
-#define MSC_SQC_MODE_BLOCK	0			/* blocking */
-#define MSC_SQC_MODE_THRU	0x100			/* through */
-#define MSC_SQC_MODE_NORMAL	0x200			/* or normal */
-#define MSC_SQC_SPLF_SH		3		/* bit# for spill flags */
-#define MSC_SQC_SPLF_M		0x1f		/* 5 bits wide */
-#define MSC_SQC_REPLYF	0x080			/* Reply queue full */
-#define MSC_SQC_REMRF	0x040			/* Remote reply queue full */
-#define MSC_SQC_USERF	0x020			/* User queue full */
-#define MSC_SQC_REMAF	0x010			/* Remote access queue full */
-#define MSC_SQC_SYSF	0x008			/* System queue full */
-#define MSC_SQC_PAUSE	0x004			/* Send Queue pause */
-#define MSC_SQC_RMODE	0x003			/* Requested mode: */
-#define MSC_SQC_RMODE_BLOCK	0			/* blocking */
-#define MSC_SQC_RMODE_THRU	1			/* through */
-#define MSC_SQC_RMODE_NORMAL	2			/* or normal */
-
-#define MSC_SQPTR0	(MSC_BASE0 + 0x8)	/* Send Queue 0 pointers */
-#define MSC_SQPTR1	(MSC_BASE0 + 0x10)	/* Send Queue 1 pointers */
-#define MSC_SQPTR2	(MSC_BASE0 + 0x18)	/* Send Queue 2 pointers */
-#define MSC_SQPTR3	(MSC_BASE0 + 0x20)	/* Send Queue 3 pointers */
-#define MSC_SQPTR4	(MSC_BASE0 + 0x28)	/* Send Queue 4 pointers */
-
-/* bits in MSC_SQPTR[0-4] */
-#define MSC_SQP_MODE	(1 << 20)		/* 64/32 word queue mode */
-#define MSC_SQP_BP_SH	17			/* bit no. for base ptr */
-#define MSC_SQP_BP_M	7			/* (it's 3 bits wide) */
-#define MSC_SQP_CNT_SH	12			/* bit no. for count */
-#define MSC_SQP_CNT_M	0x1f			/* (it's 5 bits wide) */
-#define MSC_SQP_RP_SH	6			/* bit no. for read ptr */
-#define MSC_SQP_RP_M	0x3f			/* (it's 6 bits wide() */
-#define MSC_SQP_WP_SH	0			/* bit no. for write ptr */
-#define MSC_SQP_WP_M	0x3f			/* (it's 6 bits wide() */
-
-#define MSC_OPTADR	(MSC_BASE0 + 0x30)	/* option memory address */
-
-#define MSC_MASCTRL	(MSC_BASE0 + 0x38)	/* Mem Access Sequencer ctrl */
-
-/* Bits in MSC_MASCTRL */
-#define MSC_MASC_SPAUSE	0x80			/* Send MAS pause */
-#define MSC_MASC_RPAUSE	0x40			/* Recv MAS pause */
-#define MSC_MASC_SFEXIT	0x20			/* Send MAS fault/exit */
-#define MSC_MASC_RFEXIT	0x10			/* Recv MAS fault/exit */
-#define MSC_MASC_SREADY	0x08			/* Send MAS ready */
-#define MSC_MASC_RREADY	0x04			/* Recv MAS ready */
-#define MSC_MASC_SSTOP	0x02			/* Send MAS is stopped */
-#define MSC_MASC_RSTOP	0x01			/* Recv MAS is stopped */
-
-#define MSC_SMASADR	(MSC_BASE0 + 0x40)	/* Send Mem Acc Seq address */
-#define MSC_RMASADR	(MSC_BASE0 + 0x48)	/* Recv Mem Acc Seq address */
-
-#define MSC_PID		(MSC_BASE0 + 0x50)	/* Context number (proc id) */
-
-#define MSC_QWORDCNT	(MSC_BASE0 + 0x60)	/* Queue word counts */
-
-/* Fields in MSC_QWORDCNT */
-#define MSC_QWDC_SYSCNT_SH	24		/* bit# for system count */
-#define MSC_QWDC_SYSCNT_M	0x3f		/* 6 bits wide */
-#define MSC_QWDC_SYSLEN_SH	16		/* bit# for len of sys cmd */
-#define MSC_QWDC_SYSLEN_M	0x3f		/* 6 bits wide */
-#define MSC_QWDC_USRCNT_SH	8		/* bit# for user count */
-#define MSC_QWDC_USRCNT_M	0x3f		/* 6 bits wide */
-#define MSC_QWDC_USRLEN_SH	0		/* bit# for len of user cmd */
-#define MSC_QWDC_USRLEN_M	0x3f		/* 6 bits wide */
-
-#define MSC_INTR	(MSC_BASE0 + 0x70)	/* Interrupt control/status */
-
-/* Bit offsets of interrupt fields in MSC_INTR */
-#define MSC_INTR_QBMFUL_SH	28		/* Queue buffer full intr */
-#define MSC_INTR_SQFILL_SH	24		/* Send queue fill intr */
-#define MSC_INTR_RBMISS_SH	20		/* Ring buffer miss intr */
-#define MSC_INTR_RBFULL_SH	16		/* Ring buffer full intr */
-#define MSC_INTR_RMASF_SH	12		/* Recv MAS fault intr */
-#define MSC_INTR_RMASE_SH	8		/* Recv MAS error intr */
-#define MSC_INTR_SMASF_SH	4		/* Send MAS fault intr */
-#define MSC_INTR_SMASE_SH	0		/* Send MAS error intr */
-
-#define MSC_PPIO	(MSC_BASE0 + 0x1000)	/* PArallel port I/O */
-#define MSC_PACSELECT	(MSC_BASE0 + 0x1008)	/* Performance analyser sel. */
-
-#define MSC_CIDRANGE	(MSC_BASE0 + 0x1010)	/* Rel. Cell-id range limits */
-
-/* Fields in MSC_CIDRANGE */
-#define MSC_CIDR_LRX_SH		24		/* Rel. X lower limit bit# */
-#define MSC_CIDR_LRX_M		0xFF		/* it's 8 bits wide */
-#define MSC_CIDR_HRX_SH		16		/* Rel. X upper limit bit# */
-#define MSC_CIDR_HRX_M		0xFF		/* it's 8 bits wide */
-#define MSC_CIDR_LRY_SH		8		/* Rel. Y lower limit bit# */
-#define MSC_CIDR_LRY_M		0xFF		/* it's 8 bits wide */
-#define MSC_CIDR_HRY_SH		0		/* Rel. Y upper limit bit# */
-#define MSC_CIDR_HRY_M		0xFF		/* it's 8 bits wide */
-
-#define MSC_QBMPTR	(MSC_BASE0 + 0x1018)	/* Queue buffer mgr. ptrs */
-
-/* Fields in MSC_QBMPTR */
-#define MSC_QBMP_LIM_SH		24		/* Pointer limit bit# */
-#define MSC_QBMP_LIM_M		0x3F		/* (6 bits wide) */
-#define MSC_QBMP_BP_SH		16		/* Base pointer bit# */
-#define MSC_QBMP_BP_M		0xFF		/* (8 bits wide) */
-#define MSC_QBMP_WP_SH		0		/* Write pointer bit# */
-#define MSC_QBMP_WP_M		0xFFFF		/* (16 bits wide) */
-
-#define MSC_SMASTWP	(MSC_BASE0 + 0x1030)	/* Send MAS virt page etc. */
-#define MSC_SMASREG	(MSC_BASE0 + 0x1038)	/* Send MAS context etc. */
-#define MSC_RMASTWP	(MSC_BASE0 + 0x1040)	/* Recv MAS virt page etc. */
-#define MSC_RMASREG	(MSC_BASE0 + 0x1048)	/* Recv MAS context etc. */
-
-/* Bits in MSC_[SR]MASREG */
-#define MSC_MASR_CONTEXT_SH	20		/* Context at bit 20 */
-#define MSC_MASR_CONTEXT_M	0xfff		/* 12 bits wide */
-#define MSC_MASR_AVIO		8		/* Address violation bit */
-#define MSC_MASR_CMD		7		/* MAS command bits */
-#define MSC_MASR_CMD_XFER	0		/* transfer data cmd */
-#define MSC_MASR_CMD_FOP	5		/* fetch & operate cmd */
-#define MSC_MASR_CMD_INC	6		/* increment cmd (i.e. flag) */
-#define MSC_MASR_CMD_CSI	7		/* compare & swap cmd */
-
-#define MSC_HDGERRPROC	(MSC_BASE0 + 0x1050)	/* Header gen. error process */
-#define MSC_RHDERRPROC	(MSC_BASE0 + 0x1058)	/* Recv. header decoder err. */
-
-#define MSC_SMASCNT	(MSC_BASE0 + 0x1060)	/* Send MAS counters */
-
-/* Bits in MSC_SMASCNT */
-#define MSC_SMCT_ACCSZ_SH	28		/* Access size at bit 28 */
-#define MSC_SMCT_ACCSZ_M	7		/* 3 bits wide */
-#define MSC_SMCT_MCNT_SH	8		/* M(?) count at bit 8 */
-#define MSC_SMCT_MCNT_M		0xfffff		/* 20 bits wide */
-#define MSC_SMCT_ICNT_SH	0		/* I(?) count at bit 0 */
-#define MSC_SMCT_ICNT_M		0xff		/* 8 bits wide */
-
-#define MSC_IRL		(MSC_BASE0 + 0x1070)	/* highest current int req */
-#define MSC_SIMMCHK	(MSC_BASE0 + 0x1078)	/* DRAM type installed */
-
-#define MSC_SIMMCHK_MASK 0x00000008
-
-#define MSC_SQRAM	(MSC_BASE0 + 0x2000)	/* Send Queue RAM (to +23f8) */
-
-#define MSC_VERSION	(MSC_BASE0 + 0x3000)	/* MSC+ version */
-
-#define MSC_NR_RBUFS 3
-
-#define MSC_RBMBWP0	(MSC_BASE0 + 0x4000)	/* Ring buf 0 base/write ptr */
-#define MSC_RBMMODE0	(MSC_BASE0 + 0x4008)	/* Ring buf 0 mode/context */
-#define MSC_RBMBWP1	(MSC_BASE0 + 0x4010)	/* Ring buf 1 base/write ptr */
-#define MSC_RBMMODE1	(MSC_BASE0 + 0x4018)	/* Ring buf 1 mode/context */
-#define MSC_RBMBWP2	(MSC_BASE0 + 0x4020)	/* Ring buf 2 base/write ptr */
-#define MSC_RBMMODE2	(MSC_BASE0 + 0x4028)	/* Ring buf 2 mode/context */
-
-#define MSC_RBMRP0	(MSC_BASE0 + 0x5000)	/* Ring buf 0 read pointer */
-#define MSC_RBMRP1	(MSC_BASE0 + 0x6000)	/* Ring buf 1 read pointer */
-#define MSC_RBMRP2	(MSC_BASE0 + 0x7000)	/* Ring buf 2 read pointer */
-
-/* locations of queues in virtual memory */
-#define MSC_QUEUE_BASE   0xfa800000
-#define MSC_PUT_QUEUE_S  (MSC_QUEUE_BASE + 0*PAGE_SIZE)
-#define MSC_GET_QUEUE_S  (MSC_QUEUE_BASE + 1*PAGE_SIZE)
-#define MSC_XYG_QUEUE_S  (MSC_QUEUE_BASE + 2*PAGE_SIZE)
-#define MSC_SEND_QUEUE_S  (MSC_QUEUE_BASE + 3*PAGE_SIZE)
-#define MSC_CPUT_QUEUE_S  (MSC_QUEUE_BASE + 4*PAGE_SIZE)
-#define MSC_BSEND_QUEUE_S  (MSC_QUEUE_BASE + 5*PAGE_SIZE)
-#define MSC_CXYG_QUEUE_S  (MSC_QUEUE_BASE + 6*PAGE_SIZE)
-#define MSC_CGET_QUEUE_S  (MSC_QUEUE_BASE + 7*PAGE_SIZE)
-
-/* the 4 interrupt ports - physical addresses (on bus 8) */
-#define MC_INTP_0        0x80004000
-#define MC_INTP_1        0x80005000
-#define MC_INTP_2        0x80006000
-#define MC_INTP_3        0x80007000
-
-/* the address used to send a remote signal - note that 32 pages 
- are used here - none of them are mapped to anything though */
-#define MSC_REM_SIGNAL          (MSC_QUEUE_BASE + 0x10 * PAGE_SIZE)
-
-#define MSC_PUT_QUEUE   (MSC_QUEUE_BASE + 0x100*PAGE_SIZE)
-#define MSC_GET_QUEUE   (MSC_QUEUE_BASE + 0x101*PAGE_SIZE)
-#define MSC_SEND_QUEUE  (MSC_QUEUE_BASE + 0x102*PAGE_SIZE)
-#define MSC_XY_QUEUE    (MSC_QUEUE_BASE + 0x103*PAGE_SIZE)
-#define MSC_X_QUEUE     (MSC_QUEUE_BASE + 0x104*PAGE_SIZE)
-#define MSC_Y_QUEUE     (MSC_QUEUE_BASE + 0x105*PAGE_SIZE)
-#define MSC_XYG_QUEUE   (MSC_QUEUE_BASE + 0x106*PAGE_SIZE)
-#define MSC_XG_QUEUE    (MSC_QUEUE_BASE + 0x107*PAGE_SIZE)
-#define MSC_YG_QUEUE    (MSC_QUEUE_BASE + 0x108*PAGE_SIZE)
-#define MSC_CSI_QUEUE   (MSC_QUEUE_BASE + 0x109*PAGE_SIZE)
-#define MSC_FOP_QUEUE   (MSC_QUEUE_BASE + 0x10a*PAGE_SIZE)
-
-#define SYSTEM_RINGBUF_BASE    (MSC_QUEUE_BASE + 0x200*PAGE_SIZE)
-#define SYSTEM_RINGBUF_ORDER 5
-#define SYSTEM_RINGBUF_SIZE ((1<<SYSTEM_RINGBUF_ORDER)*PAGE_SIZE)
-
-#define MSC_SYSTEM_DIRECT	(MSC_QUEUE_BASE + 0x700 * PAGE_SIZE)
-#define MSC_USER_DIRECT		(MSC_QUEUE_BASE + 0x701 * PAGE_SIZE)
-#define MSC_REMOTE_DIRECT	(MSC_QUEUE_BASE + 0x702 * PAGE_SIZE)
-#define MSC_REPLY_DIRECT	(MSC_QUEUE_BASE + 0x703 * PAGE_SIZE)
-#define MSC_REMREPLY_DIRECT	(MSC_QUEUE_BASE + 0x704 * PAGE_SIZE)
-
-#define MSC_SYSTEM_DIRECT_END	(MSC_QUEUE_BASE + 0x708 * PAGE_SIZE)
-#define MSC_USER_DIRECT_END	(MSC_QUEUE_BASE + 0x709 * PAGE_SIZE)
-#define MSC_REMOTE_DIRECT_END	(MSC_QUEUE_BASE + 0x70a * PAGE_SIZE)
-#define MSC_REPLY_DIRECT_END	(MSC_QUEUE_BASE + 0x70b * PAGE_SIZE)
-#define MSC_REMREPLY_DIRECT_END	(MSC_QUEUE_BASE + 0x70c * PAGE_SIZE)
-
-/* AP1000+ Memory Controller (MC+) */
-
-#define MC_BASE0	0xfa000000
-
-#define MC_DRAM_CTRL	(MC_BASE0 + 0x0)	/* DRAM control */
-#define MC_DRAM_CHKBIT	(MC_BASE0 + 0x8)	/* DRAM check bits */
-#define MC_DRAM_ERRADR	(MC_BASE0 + 0x10)	/* DRAM error address */
-#define MC_DRAM_ERRSYN	(MC_BASE0 + 0x18)	/* DRAM error syndrome */
-
-#define MC_FREERUN	(MC_BASE0 + 0x20)	/* Free run ctr (12.5MHz) */
-#define MC_ITIMER0	(MC_BASE0 + 0x28)	/* Interval timer 0 */
-#define MC_ITIMER1	(MC_BASE0 + 0x30)	/* Interval timer 1 */
-
-#define MC_INTR		(MC_BASE0 + 0x38)	/* Interrupt control/status */
-
-/* Interrupt control/status fields in MC_INTR */
-#define MC_INTR_ECCD_SH		12		/* ECC double (uncorr.) err */
-#define MC_INTR_ECCS_SH		8		/* ECC single (corr.) error */
-#define MC_INTR_ITIM1_SH	4		/* Interval timer 1 intr */
-#define MC_INTR_ITIM0_SH	0		/* Interval timer 0 intr */
-
-#define MC_CTP		(MC_BASE0 + 0x50)	/* Context table pointer */
-
-#define MC_VBUS_FAST	(MC_BASE0 + 0x60)	/* VBus fast data mode ctrl */
-
-#define MC_INTR_PORT	(MC_BASE0 + 0x68)	/* Interrupt port ctrl/stat */
-
-/* Interrupt control/status fields in MC_INTR_PORT */
-#define MC_INTP_3_SH		12		/* port 0 (880007000) */
-#define MC_INTP_2_SH		8		/* port 1 (880006000) */
-#define MC_INTP_1_SH		4		/* port 1 (880005000) */
-#define MC_INTP_0_SH		0		/* port 1 (880004000) */
-
-#define MC_PAC_COUNT	(MC_BASE0 + 0x1000)	/* Perf. an. counters */
-#define MC_PAC_SELECT	(MC_BASE0 + 0x1008)	/* Perf. an. ctr. select */
-
-#define MC_VERSION	(MC_BASE0 + 0x3000)	/* MC+ version/date */
-
-#define MC_MMU_TLB4K	(MC_BASE0 + 0x6000)	/* MC+ TLB for 4k pages */
-#define MC_MMU_TLB256K	(MC_BASE0 + 0x7000)	/* MC+ TLB for 256k pages */
-#define MC_MMU_TLB4K_SIZE 256
-#define MC_MMU_TLB256K_SIZE 64
-
-
-/*
- * Bit values for a standard AP1000 3-bit interrupt control/status field.
- */
-#define AP_INTR_REQ		1	/* interrupt request bit */
-#define AP_INTR_MASK		2	/* interrupt mask bit (1 disables) */
-#define AP_INTR_WENABLE		4	/* enable write to mask/req bits */
-#define AP_CLR_INTR_REQ		4	/* clear req. bit (dismiss intr) */
-#define AP_CLR_INTR_MASK	5	/* clear mask bit (enable ints) */
-#define AP_SET_INTR_REQ		6	/* set request bit */
-#define AP_SET_INTR_MASK	7	/* set mask bit (disable ints) */
-
-/*
- * Bit field extraction/insertion macros.
- */
-#define EXTFIELD(val, fld)	(((val) >> fld ## _SH) & fld ## _M)
-#define MKFIELD(val, fld)	(((val) & fld ## _M) << fld ## _SH)
-#define INSFIELD(dst, val, fld)	(((dst) & ~(fld ## _M << fld ## _SH)) \
-				 | MKFIELD(val, fld))
-
-/* 
- * RTC registers 
- */
-#define RTC 0xfff10000	/*	RTC system mode	*/
-#define RTC_CSR 	(RTC+0x0010)	/* RTC control	register   */
-#define RTC_STR   	(RTC+0x0020)	/* RTC status register	  */
-#define RTC_ITRR   	(RTC+0x0030)	/* RTC interrupt register  */
-#define RTC_RSTR   	(RTC+0x0070)	/* RTC reset register	   */	 
-#define RTC_RSTR_TR		0x00008000	/* RTC through mode */
-#define RTC_RSTR_TS		0x00004000	/* RTC test mode    */
-#define RTC_RSTR_ED		0x00002000	/* RTC reverse mode    */
-#define RTC_RSTR_AC		0x00001000	/* RTC long mode	*/
-#define RTC_RSTR_SN		0x00000800	/* SOUTH/NORTH direction */
-#define RTC_RSTR_EW		0x00000400	/* EAST/WEST direction	 */
-#define RTC_RSTR_NC		0x00000200	/* get NORTH channel   */
-#define RTC_RSTR_SC		0x00000100	/* get SOUTH channel	*/
-#define RTC_RSTR_WC		0x00000080	/* get WEST channel	*/
-#define RTC_RSTR_EC		0x00000040	/* get EAST channel	*/
-#define RTC_RSTR_BM		0x00000020	/* broad also my cell	*/
-#define RTC_RSTR_RT		0x00000020	/* reset  		*/
-
-
-#define RTC_ITRR_PA		0x00040000	/* parity error for LBUS */
-#define RTC_ITRR_LR		0x00020000	/* MSC read but FIFO is empty*/
-#define RTC_ITRR_LW		0x00010000	/* MSC write but FIFO is full*/
-#define RTC_ITRR_AL		0x00008000	/* specify end data in data transfer */
-#define RTC_ITRR_DN		0x00002000	/* parity error in NORTH channel  */
-#define RTC_ITRR_DS		0x00001000	/* parity error in SOUTH channel		*/
-#define RTC_ITRR_DW		0x00000800	/* parity error in WEST channel			*/
-#define RTC_ITRR_DE		0x00000400	/* parity error in EAST channel			*/
-#define RTC_ITRR_BD		0x00000200	/* receive 2 kind of broad data			*/
-#define RTC_ITRR_EW		0x00000100	/* control to write error bits			*/
-#define RTC_ITRR_EM		0x00000080	/* mask error interrupt request			*/
-#define RTC_ITRR_ER		0x00000040	/* error interrput request				*/
-#define RTC_ITRR_SW		0x00000020	/* control to write SR, SM  */
-#define RTC_ITRR_SM		0x00000010	/* mask send interrupt					*/
-#define RTC_ITRR_SR		0x00000008	/* send interrupt request				*/
-#define RTC_ITRR_RW		0x00000004	/* icontrol to read RR, RM				*/
-#define RTC_ITRR_RM		0x00000002	/* mask read interrupt					*/
-#define RTC_ITRR_RR		0x00000001	/* receive interrupt request			*/
-
-#define RTC_ITRR_RWM (RTC_ITRR_RW|RTC_ITRR_RM)
-#define RTC_ITRR_SWM (RTC_ITRR_SW|RTC_ITRR_SM)
-#define RTC_ITRR_EWM (RTC_ITRR_EW|RTC_ITRR_EM)
-#define RTC_ITRR_RWR (RTC_ITRR_RW|RTC_ITRR_RR)
-#define RTC_ITRR_SWR (RTC_ITRR_SW|RTC_ITRR_SR)
-#define RTC_ITRR_EWR (RTC_ITRR_EW|RTC_ITRR_ER)
-#define RTC_ITRR_RRM (RTC_ITRR_RM|RTC_ITRR_RR)
-#define RTC_ITRR_SRM (RTC_ITRR_SM|RTC_ITRR_SR)
-#define RTC_ITRR_ERM (RTC_ITRR_EM|RTC_ITRR_ER)
-#define RTC_ITRR_RWMR   (RTC_ITRR_RW|RTC_ITRR_RM|RTC_ITRR_RR)
-#define RTC_ITRR_SWMR   (RTC_ITRR_SW|RTC_ITRR_SM|RTC_ITRR_SR)
-#define RTC_ITRR_EWMR   (RTC_ITRR_EW|RTC_ITRR_EM|RTC_ITRR_ER)
-
-#define RTC_ITRR_ALLMSK (RTC_ITRR_RWM|RTC_ITRR_SWM|RTC_ITRR_EWM)
-#define RTC_ITRR_ALLCLR (RTC_ITRR_RW|RTC_ITRR_SW|RTC_ITRR_EW)
-#define RTC_ITRR_ALLWR  (RTC_ITRR_RWMR|RTC_ITRR_SWMR|RTC_ITRR_EWMR)
-#define RTC_ITRR_ALLRD  (RTC_ITRR_RRM|RTC_ITRR_SRM|RTC_ITRR_ERM)
-
-
-/*
- * macros to manipulate context/task/pid numbers for parallel programs
- */
-#define MPP_CONTEXT_BASE (AP_NUM_CONTEXTS - (NR_TASKS - MPP_TASK_BASE))
-#define MPP_TASK_TO_CTX(taskid) (((taskid) - MPP_TASK_BASE)+MPP_CONTEXT_BASE)
-#define MPP_CTX_TO_TASK(ctx) (((ctx)-MPP_CONTEXT_BASE)+MPP_TASK_BASE)
-#define MPP_IS_PAR_TASK(taskid) ((taskid) >= MPP_TASK_BASE)
-#define MPP_IS_PAR_CTX(ctx) ((ctx) >= MPP_CONTEXT_BASE)
-
-
-/*
- * ioctls available on the ring buffer
- */
-#define CAP_GETINIT 1
-#define CAP_SYNC    2
-#define CAP_SETTASK 3
-#define CAP_SETGANG 4
-#define CAP_MAP     5
-
-/*
- * the structure shared by the kernel and the parallel tasks in the
- * front of the cap_shared area
- */
-#ifndef _ASM_
-#ifdef _APLIB_
-struct _kernel_cap_shared {
-	unsigned rbuf_read_ptr;
-	unsigned dummy[32]; /* for future expansion */
-};
-#endif
-#endif
-
-/*
- * the mmap'd ringbuffer region is layed out like this:
-
- shared page - one page
- queue pages - 11 pages
- ring buffer - xx pages
- mirror of ring buffer - xx pages
- */
-#define RBUF_VBASE 0xd0000000
-#define RBUF_SHARED_PAGE_OFF 0
-#define RBUF_PUT_QUEUE             PAGE_SIZE
-#define RBUF_GET_QUEUE           2*PAGE_SIZE
-#define RBUF_SEND_QUEUE          3*PAGE_SIZE
-#define RBUF_XY_QUEUE            4*PAGE_SIZE
-#define RBUF_X_QUEUE             5*PAGE_SIZE
-#define RBUF_Y_QUEUE             6*PAGE_SIZE
-#define RBUF_XYG_QUEUE           7*PAGE_SIZE
-#define RBUF_XG_QUEUE            8*PAGE_SIZE
-#define RBUF_YG_QUEUE            9*PAGE_SIZE
-#define RBUF_CSI_QUEUE          10*PAGE_SIZE
-#define RBUF_FOP_QUEUE          11*PAGE_SIZE
-#define RBUF_RING_BUFFER_OFFSET 15*PAGE_SIZE
-
-
-/*
- * number of MMU contexts to use
- */
-#define AP_NUM_CONTEXTS 1024
-#define SYSTEM_CONTEXT 1
-
-/*
- * the default gang scheduling factor
-*/
-#define DEF_GANG_FACTOR 15
-
-/*
- * useful for bypassing the cache
-*/
-#ifdef _APLIB_
-#ifndef _ASM_
-static inline unsigned long phys_8_in(unsigned long paddr)
-{
-	unsigned long word;
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (word) :
-			     "r" (paddr), "i" (0x28) :
-			     "memory");
-	return word;
-}
-
-/*
- * useful for bypassing the cache
-*/
-static inline unsigned long phys_9_in(unsigned long paddr)
-{
-	unsigned long word;
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (word) :
-			     "r" (paddr), "i" (0x29) :
-			     "memory");
-	return word;
-}
-#endif
-#endif
-
-/*
- * DDV definitions 
-*/
-#define OBASE        (0xfff40010)
-#define OPTION_BASE 0xfc000000
-#define _OPIBUS_BASE (OPTION_BASE + 0x800000)
-#ifdef CAP2_OPTION
-#define OPIBUS_BASE 0
-#else
-#define OPIBUS_BASE _OPIBUS_BASE
-#endif
-#define PBUF0        (OPIBUS_BASE+0x7e0080)
-#define PBUF1        (OPIBUS_BASE+0x7e0084)
-#define PBUF2        (OPIBUS_BASE+0x7e0088)
-#define PBUF3        (OPIBUS_BASE+0x7e008c)
-#define PIRQ         (OPIBUS_BASE+0x7e0090)
-#define PRST         (OPIBUS_BASE+0x7e0094)
-
-#define IRC0         (OPIBUS_BASE+0x7d00a0)
-#define IRC1         (OPIBUS_BASE+0x7d00a4)
-
-#define PRST_IRST    (0x00000001)
-
-#define OPIU_RESET			(0x00000000)
-#define OPIU_OP				(PBUF0)
-
-#define LSTR(s) (_OPIBUS_BASE + (s))
-
-#endif /* _AP1000_APREG_H */
-
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/ap1000/apservice.h linux/include/asm-sparc/ap1000/apservice.h
--- v2.3.41/linux/include/asm-sparc/ap1000/apservice.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/ap1000/apservice.h	Wed Dec 31 16:00:00 1969
@@ -1,111 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* this defines service requests that can be made by the cells of the 
-   front end "bootap" server 
-
-   tridge, March 1996
-   */
-#ifndef _APSERVICE_H
-#define _APSERVICE_H
-#ifdef __KERNEL__
-#include <linux/sched.h>
-#endif
-
-#ifndef _ASM_
-
-/* all requests start with this structure */
-struct cap_request {
-  unsigned header; /* for the hardware */
-  int size; /* the total request size in bytes, including this header */
-  int cid; /* the cell it came from */
-  int type; /* the type of request */
-  int data[4]; /* misc data */
-};
-
-/* Initialisation data to be sent to boot cell program */
-struct cap_init {
-  int bootcid;  /* base cid to boot */
-  int numcells; /* number of cells */
-  int physcells; /* physical number of cells */
-  unsigned long baseIP; /* IP address of cell 0 */
-  unsigned long netmask; /* netmask of cells net */
-  int gdbcell; /* what cell is the debugger running on */
-  unsigned init_time; /* time at startup */
-};
-#endif
-
-/* what fake host number to use for the aliased IP device */
-#define AP_ALIAS_IP 2
-
-/* request types */
-#define REQ_WRITE 0
-#define REQ_SHUTDOWN 1
-#define REQ_LOAD_AOUT 2
-#define REQ_PUTCHAR 3
-#define REQ_GETBOOTARGS 4       
-#define REQ_PUTDEBUGCHAR 5      
-#define REQ_GETDEBUGCHAR 6     
-#define REQ_OPENNET 7
-#define REQ_IP 8
-#define REQ_BREAK 9
-#define REQ_INIT 10
-#define REQ_PUTDEBUGSTRING 11
-#define REQ_BREAD 12
-#define REQ_BWRITE 13
-#define REQ_BOPEN 14
-#define REQ_BCLOSE 15
-#define REQ_DDVOPEN 16
-#define REQ_BIF_TOKEN 17
-#define REQ_KILL 18
-#define REQ_SCHEDULE 19
-
-/* the bit used to indicate that the host wants the BIF */
-#define HOST_STATUS_BIT 2
-
-#ifdef __KERNEL__
-/* some prototypes */
-extern int ap_dma_wait(int ch);
-extern int ap_dma_go(unsigned long ch,unsigned int p,int size,unsigned long cmd);
-extern int mpp_cid(void);
-extern void ap_start_debugger(void);
-extern int bif_queue(struct cap_request *req,char *buf,int bufsize);
-extern void write_bif_polled(char *buf1,int len1,char *buf2,int len2);
-extern void read_bif(char *buf,int size);
-extern void ap_wait_request(struct cap_request *req,int type);
-extern void bif_set_poll(int set);
-extern void ap_led(unsigned char d);
-extern void ap_xor_led(unsigned char d);
-extern void ap_set_led(unsigned char d);
-extern void ap_unset_led(unsigned char d);
-extern void bif_toss(int size);
-void ap_msc_init(void);
-void mac_dma_complete(void);
-void ap_dbg_flush(void);
-void bif_queue_flush(void);
-/* void ap_printk(char *msg,int a1,int a2,int a3,int a4,int a5); */
-void show_mapping_ctx(unsigned *ctp,int context,unsigned Vm);
-void async_fault(unsigned long address, int write, int taskid,
-		 void (*callback)(int,unsigned long,int,int));
-void ap_bif_init(void);
-void ap_tnet_init(void);
-int wait_on_int(volatile int *p,int x,int interval);
-void ap_put(int dest_cell,u_long local_addr,int size,
-	    u_long remote_addr,u_long dest_flag,u_long local_flag);
-void ap_bput(u_long local_addr,int size,
-	     u_long remote_addr,u_long dest_flag,u_long local_flag);
-void msc_switch_check(struct task_struct *tsk);
-int bif_queue_nocopy(struct cap_request *req,char *buf,int bufsize);
-void mpp_set_gang_factor(int factor);
-void bif_register_request(int type,void (*fn)(struct cap_request *));
-void bif_add_debug_key(char key,void (*fn)(void),char *description);
-void ap_complete(struct cap_request *creq);
-void ap_reboot(char *bootstr);
-#endif
-
-
-#endif /* _APSERVICE_H */
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/ap1000/pgtapmmu.h linux/include/asm-sparc/ap1000/pgtapmmu.h
--- v2.3.41/linux/include/asm-sparc/ap1000/pgtapmmu.h	Tue Aug  4 16:03:35 1998
+++ linux/include/asm-sparc/ap1000/pgtapmmu.h	Wed Dec 31 16:00:00 1969
@@ -1,141 +0,0 @@
-  /*
-   * Copyright 1996 The Australian National University.
-   * Copyright 1996 Fujitsu Laboratories Limited
-   * 
-   * This software may be distributed under the terms of the Gnu
-   * Public License version 2 or later
-  */
-/* 
- * based on pgtsrmmu.h
- *
- */
-
-#ifndef _SPARC_PGTAPMMU_H
-#define _SPARC_PGTAPMMU_H
-
-#include <asm/page.h>
-#include <asm/ap1000/apreg.h>
-
-
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define APMMU_PMD_SHIFT         18
-#define APMMU_PMD_SIZE          (1UL << APMMU_PMD_SHIFT)
-#define APMMU_PMD_MASK          (~(APMMU_PMD_SIZE-1))
-#define APMMU_PMD_ALIGN(addr)   (((addr)+APMMU_PMD_SIZE-1)&APMMU_PMD_MASK)
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define APMMU_PGDIR_SHIFT       24
-#define APMMU_PGDIR_SIZE        (1UL << APMMU_PGDIR_SHIFT)
-#define APMMU_PGDIR_MASK        (~(APMMU_PGDIR_SIZE-1))
-#define APMMU_PGDIR_ALIGN(addr) (((addr)+APMMU_PGDIR_SIZE-1)&APMMU_PGDIR_MASK)
-
-#define APMMU_PTRS_PER_PTE      64
-#define APMMU_PTRS_PER_PMD      64
-#define APMMU_PTRS_PER_PGD      256
-
-#define APMMU_PTE_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
-#define APMMU_PMD_TABLE_SIZE    0x100 /* 64 entries, 4 bytes a piece */
-#define APMMU_PGD_TABLE_SIZE    0x400 /* 256 entries, 4 bytes a piece */
-
-#define APMMU_VMALLOC_START   (0xfe300000)
-#define APMMU_VMALLOC_END     ~0x0UL
-
-/* Definition of the values in the ET field of PTD's and PTE's */
-#define APMMU_ET_MASK         0x3
-#define APMMU_ET_INVALID      0x0
-#define APMMU_ET_PTD          0x1
-#define APMMU_ET_PTE          0x2
-#define APMMU_ET_REPTE        0x3 /* AIEEE, SuperSparc II reverse endian page! */
-
-/* Physical page extraction from PTP's and PTE's. */
-#define APMMU_CTX_PMASK    0xfffffff0
-#define APMMU_PTD_PMASK    0xfffffff0
-#define APMMU_PTE_PMASK    0xffffff00
-
-/* The pte non-page bits.  Some notes:
- * 1) cache, dirty, valid, and ref are frobbable
- *    for both supervisor and user pages.
- * 2) exec and write will only give the desired effect
- *    on user pages
- * 3) use priv and priv_readonly for changing the
- *    characteristics of supervisor ptes
- */
-#define APMMU_CACHE        0x80
-#define APMMU_DIRTY        0x40
-#define APMMU_REF          0x20
-#define APMMU_EXEC         0x08
-#define APMMU_WRITE        0x04
-#define APMMU_VALID        0x02 /* APMMU_ET_PTE */
-#define APMMU_PRIV         0x1c
-#define APMMU_PRIV_RDONLY  0x18
-
-#define APMMU_CHG_MASK    (0xffffff00 | APMMU_REF | APMMU_DIRTY)
-
-/*
- * "normal" sun systems have their memory on bus 0. This means the top
- * 4 bits of 36 bit physical addresses are 0. We use this define to
- * determine if a piece of memory might be normal memory, or if its
- * definately some sort of device memory.  
- *
- * On the AP+ normal memory is on bus 8. Why? Ask Fujitsu :-)
-*/
-#define MEM_BUS_SPACE 8
-
-/* Some day I will implement true fine grained access bits for
- * user pages because the APMMU gives us the capabilities to
- * enforce all the protection levels that vma's can have.
- * XXX But for now...
- */
-#define APMMU_PAGE_NONE    __pgprot((MEM_BUS_SPACE<<28) | \
-				    APMMU_VALID | APMMU_CACHE | \
-				    APMMU_PRIV | APMMU_REF)
-#define APMMU_PAGE_SHARED  __pgprot((MEM_BUS_SPACE<<28) | \
-				    APMMU_VALID | APMMU_CACHE | \
-				    APMMU_EXEC | APMMU_WRITE | APMMU_REF)
-#define APMMU_PAGE_COPY    __pgprot((MEM_BUS_SPACE<<28) | \
-				    APMMU_VALID | APMMU_CACHE | \
-				    APMMU_EXEC | APMMU_REF)
-#define APMMU_PAGE_RDONLY  __pgprot((MEM_BUS_SPACE<<28) | \
-				    APMMU_VALID | APMMU_CACHE | \
-				    APMMU_EXEC | APMMU_REF)
-#define APMMU_PAGE_KERNEL  __pgprot((MEM_BUS_SPACE<<28) | \
-				    APMMU_VALID | APMMU_CACHE | APMMU_PRIV | \
-				    APMMU_DIRTY | APMMU_REF)
-
-#define APMMU_CTXTBL_PTR         0x00000100
-#define APMMU_CTX_REG            0x00000200
-
-extern __inline__ unsigned long apmmu_get_ctable_ptr(void)
-{
-	unsigned int retval;
-
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (retval) :
-			     "r" (APMMU_CTXTBL_PTR),
-			     "i" (ASI_M_MMUREGS));
-	return (retval & APMMU_CTX_PMASK) << 4;
-}
-
-extern __inline__ void apmmu_set_context(int context)
-{
-	__asm__ __volatile__("sta %0, [%1] %2\n\t" : :
-			     "r" (context), "r" (APMMU_CTX_REG),
-			     "i" (ASI_M_MMUREGS) : "memory");
-	/* The AP1000+ message controller also needs to know
-	   the current task's context. */
-	MSC_OUT(MSC_PID, context);
-}
-
-extern __inline__ int apmmu_get_context(void)
-{
-	register int retval;
-	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
-			     "=r" (retval) :
-			     "r" (APMMU_CTX_REG),
-			     "i" (ASI_M_MMUREGS));
-	return retval;
-}
-
-#endif /* !(_SPARC_PGTAPMMU_H) */
-
-
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/checksum.h linux/include/asm-sparc/checksum.h
--- v2.3.41/linux/include/asm-sparc/checksum.h	Fri Jan  7 19:13:22 2000
+++ linux/include/asm-sparc/checksum.h	Mon Jan 31 23:41:14 2000
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.30 2000/01/05 21:27:39 davem Exp $ */
+/* $Id: checksum.h,v 1.31 2000/01/31 01:26:52 davem Exp $ */
 #ifndef __SPARC_CHECKSUM_H
 #define __SPARC_CHECKSUM_H
 
@@ -210,7 +210,7 @@
 
 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
 						     struct in6_addr *daddr,
-						     __u16 len,
+						     __u32 len,
 						     unsigned short proto,
 						     unsigned int sum) 
 {
@@ -237,7 +237,7 @@
 		"
 		: "=&r" (sum)
 		: "r" (saddr), "r" (daddr), 
-		  "r"(htonl((__u32) (len))), "r"(htonl(proto)), "r"(sum)
+		  "r"(htonl(len)), "r"(htonl(proto)), "r"(sum)
 		: "g2", "g3", "g4", "cc");
 
 	return csum_fold(sum);
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/ethtool.h linux/include/asm-sparc/ethtool.h
--- v2.3.41/linux/include/asm-sparc/ethtool.h	Wed Mar 10 16:53:37 1999
+++ linux/include/asm-sparc/ethtool.h	Mon Jan 31 23:37:19 2000
@@ -1,7 +1,7 @@
-/* $Id: ethtool.h,v 1.1 1998/12/19 15:09:38 davem Exp $
+/* $Id: ethtool.h,v 1.2 2000/01/31 04:59:17 davem Exp $
  * ethtool.h: Defines for SparcLinux ethtool.
  *
- * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
  */
 
 #ifndef _SPARC_ETHTOOL_H
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v2.3.41/linux/include/asm-sparc/page.h	Tue Jan 11 22:31:44 2000
+++ linux/include/asm-sparc/page.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.46 2000/01/08 16:38:22 anton Exp $
+/* $Id: page.h,v 1.47 2000/01/29 00:41:49 anton Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -92,132 +92,6 @@
 #define __ctxd(x)	((ctxd_t) { (x) } )
 #define __pgprot(x)	((pgprot_t) { (x) } )
 #define __iopgprot(x)	((iopgprot_t) { (x) } )
-
-#elif CONFIG_AP1000_DEBUG
-
-typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned long iopte; } iopte_t;
-typedef struct { unsigned long pmd; } pmd_t;
-typedef struct { unsigned long pgd; } pgd_t;
-typedef struct { unsigned long ctxd; } ctxd_t;
-typedef struct { unsigned long pgprot; } pgprot_t;
-typedef struct { unsigned long iopgprot; } iopgprot_t;
-
-static inline unsigned long __get_val(unsigned long x)
-{
-	if ((x & 0xF0000000) == (8<<28))
-		return x & 0x0FFFFFFF;
-	return x;
-}
-
-static inline unsigned long __set_val(unsigned long x)
-{
-	if ((x & 0xF0000000) == (0<<28))
-		return x | 0x80000000;
-	return x;
-}
-
-#define __pte_val(x)	((x).pte)
-#define __iopte_val(x)	((x).iopte)
-#define __pmd_val(x)      ((x).pmd)
-#define __pgd_val(x)	((x).pgd)
-#define __ctxd_val(x)	((x).ctxd)
-#define __pgprot_val(x)	((x).pgprot)
-#define __iopgprot_val(x)	((x).iopgprot)
-
-#define ___pte(x)	((pte_t) { (x) } )
-#define ___iopte(x)	((iopte_t) { (x) } )
-#define ___pmd(x)        ((pmd_t) { (x) } )
-#define ___pgd(x)	((pgd_t) { (x) } )
-#define ___ctxd(x)	((ctxd_t) { (x) } )
-#define ___pgprot(x)	((pgprot_t) { (x) } )
-#define ___iopgprot(x)	((iopgprot_t) { (x) } )
-
-
-#define pte_val(x) __get_val(__pte_val(x))
-#define iopte_val(x) __get_val(__iopte_val(x))
-#define pmd_val(x) __get_val(__pmd_val(x))
-#define pgd_val(x) __get_val(__pgd_val(x))
-#define ctxd_val(x) __get_val(__ctxd_val(x))
-#define pgprot_val(x) __get_val(__pgprot_val(x))
-#define iopgprot_val(x) __get_val(__iopgprot_val(x))
-
-#define __pte(x) ___pte(__set_val(x))
-#define __iopte(x) ___iopte(__set_val(x))
-#define __pmd(x) ___pmd(__set_val(x))
-#define __pgd(x) ___pgd(__set_val(x))
-#define __ctxd(x) ___ctxd(__set_val(x))
-#define __pgprot(x) ___pgprot(x)
-#define __iopgprot(x) ___iopgprot(__set_val(x))
-
-#elif CONFIG_AP1000
-
-typedef unsigned long pte_t;
-typedef unsigned long iopte_t;
-typedef unsigned long pmd_t;
-typedef unsigned long pgd_t;
-typedef unsigned long ctxd_t;
-typedef unsigned long pgprot_t;
-typedef unsigned long iopgprot_t;
-
-static inline unsigned long __get_val(unsigned long x)
-{
-#if 0
-	extern void ap_panic(char *fmt,...);
-	if (x && (x & 0xF0000000) == 0) {
-		ap_panic("get_val got 0x%x\n",x);
-	}
-#endif
-	if ((x & 0xF0000000) == (8<<28))
-		return x & 0x0FFFFFFF;
-	return x;
-}
-
-static inline unsigned long __set_val(unsigned long x)
-{
-#if 0
-	extern void ap_panic(char *fmt,...);
-	if ((x & 0xF0000000) == (8<<28)) {
-		ap_panic("set_val got 0x%x\n",x);
-	}
-#endif
-	if ((x & 0xF0000000) == (0<<28))
-		return x | 0x80000000;
-	return x;
-}
-
-#define __pte_val(x)	(x)
-#define __iopte_val(x)	(x)
-#define __pmd_val(x)      (x)
-#define __pgd_val(x)	(x)
-#define __ctxd_val(x)	(x)
-#define __pgprot_val(x)	(x)
-#define __iopgprot_val(x)	(x)
-
-#define ___pte(x)	((pte_t) { (x) } )
-#define ___iopte(x)	((iopte_t) { (x) } )
-#define ___pmd(x)        ((pmd_t) { (x) } )
-#define ___pgd(x)	((pgd_t) { (x) } )
-#define ___ctxd(x)	((ctxd_t) { (x) } )
-#define ___pgprot(x)	((pgprot_t) { (x) } )
-#define ___iopgprot(x)	((iopgprot_t) { (x) } )
-
-
-#define pte_val(x) __get_val(__pte_val(x))
-#define iopte_val(x) __get_val(__iopte_val(x))
-#define pmd_val(x) __get_val(__pmd_val(x))
-#define pgd_val(x) __get_val(__pgd_val(x))
-#define ctxd_val(x) __get_val(__ctxd_val(x))
-#define pgprot_val(x) __get_val(__pgprot_val(x))
-#define iopgprot_val(x) __get_val(__iopgprot_val(x))
-
-#define __pte(x) ___pte(__set_val(x))
-#define __iopte(x) ___iopte(__set_val(x))
-#define __pmd(x) ___pmd(__set_val(x))
-#define __pgd(x) ___pgd(__set_val(x))
-#define __ctxd(x) ___ctxd(__set_val(x))
-#define __pgprot(x) ___pgprot(x)
-#define __iopgprot(x) ___iopgprot(__set_val(x))
 
 #else
 /*
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h
--- v2.3.41/linux/include/asm-sparc/sbus.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc/sbus.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.20 1999/12/27 06:37:17 anton Exp $
+/* $Id: sbus.h,v 1.21 2000/01/28 13:43:11 jj Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/scatterlist.h linux/include/asm-sparc/scatterlist.h
--- v2.3.41/linux/include/asm-sparc/scatterlist.h	Tue Jan  4 13:57:19 2000
+++ linux/include/asm-sparc/scatterlist.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: scatterlist.h,v 1.4 1999/12/27 06:37:20 anton Exp $ */
+/* $Id: scatterlist.h,v 1.5 2000/01/29 16:27:07 jj Exp $ */
 #ifndef _SPARC_SCATTERLIST_H
 #define _SPARC_SCATTERLIST_H
 
@@ -13,6 +13,9 @@
     __u32 dvma_address; /* A place to hang host-specific addresses at. */
     __u32 dvma_length;
 };
+
+#define sg_dma_address(sg) ((sg)->dvma_address)
+#define sg_dma_len(sg)     ((sg)->dvma_length)
 
 #define ISA_DMA_THRESHOLD (~0UL)
 
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h
--- v2.3.41/linux/include/asm-sparc/siginfo.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc/siginfo.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: siginfo.h,v 1.6 2000/01/21 11:39:17 jj Exp $
+/* $Id: siginfo.h,v 1.7 2000/01/29 07:41:51 davem Exp $
  * siginfo.c:
  */
 
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/types.h linux/include/asm-sparc/types.h
--- v2.3.41/linux/include/asm-sparc/types.h	Mon Jan 12 15:15:54 1998
+++ linux/include/asm-sparc/types.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: types.h,v 1.11 1997/12/22 13:28:22 mj Exp $ */
+/* $Id: types.h,v 1.12 2000/01/29 02:23:25 anton Exp $ */
 #ifndef _SPARC_TYPES_H
 #define _SPARC_TYPES_H
 
@@ -44,6 +44,8 @@
 typedef unsigned long long u64;
 
 #define BITS_PER_LONG 32
+
+typedef u32 dma_addr_t;
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v2.3.41/linux/include/asm-sparc/unistd.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc/unistd.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.64 2000/01/16 06:20:32 davem Exp $ */
+/* $Id: unistd.h,v 1.66 2000/01/29 17:57:25 jj Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -161,7 +161,7 @@
 /* #define __NR_ni_syscall      143    ENOSYS under SunOS                          */
 #define __NR_getrlimit          144 /* Common                                      */
 #define __NR_setrlimit          145 /* Common                                      */
-/* #define __NR_killpg          146    SunOS Specific                              */
+#define __NR_pivot_root		146 /* Linux Specific, killpg under SunOS          */
 #define __NR_prctl		147 /* ENOSYS under SunOS                          */
 #define __NR_pciconfig_read	148 /* ENOSYS under SunOS                          */
 #define __NR_pciconfig_write	149 /* ENOSYS under SunOS                          */
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h
--- v2.3.41/linux/include/asm-sparc64/checksum.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/checksum.h	Mon Jan 31 23:41:14 2000
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.15 2000/01/19 04:06:09 davem Exp $ */
+/* $Id: checksum.h,v 1.16 2000/01/31 01:26:54 davem Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -167,7 +167,7 @@
 
 static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
 						     struct in6_addr *daddr,
-						     __u16 len,
+						     __u32 len,
 						     unsigned short proto,
 						     unsigned int sum) 
 {
@@ -192,7 +192,7 @@
 	addccc		%%g3, %%g7, %0
 	addc		0, %0, %0
 "	: "=&r" (sum)
-	: "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))),
+	: "r" (saddr), "r" (daddr), "r"(htonl(len)),
 	  "r"(htonl(proto)), "r"(sum)
 	: "g2", "g3", "g7", "cc");
 
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h
--- v2.3.41/linux/include/asm-sparc64/dma.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/dma.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: dma.h,v 1.18 1999/12/01 10:47:22 davem Exp $
+/* $Id: dma.h,v 1.19 2000/01/28 13:43:14 jj Exp $
  * include/asm-sparc64/dma.h
  *
  * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/ethtool.h linux/include/asm-sparc64/ethtool.h
--- v2.3.41/linux/include/asm-sparc64/ethtool.h	Wed Mar 10 16:53:38 1999
+++ linux/include/asm-sparc64/ethtool.h	Mon Jan 31 23:37:19 2000
@@ -1,7 +1,7 @@
-/* $Id: ethtool.h,v 1.1 1998/12/19 15:09:40 davem Exp $
+/* $Id: ethtool.h,v 1.2 2000/01/31 04:59:19 davem Exp $
  * ethtool.h: Defines for SparcLinux ethtool.
  *
- * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
  */
 
 #ifndef _SPARC64_ETHTOOL_H
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.3.41/linux/include/asm-sparc64/floppy.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/floppy.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.24 2000/01/09 15:16:34 ecd Exp $
+/* $Id: floppy.h,v 1.25 2000/01/28 13:43:14 jj Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h
--- v2.3.41/linux/include/asm-sparc64/io.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/io.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.29 1999/12/20 04:58:42 davem Exp $ */
+/* $Id: io.h,v 1.30 2000/01/28 13:43:14 jj Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/parport.h linux/include/asm-sparc64/parport.h
--- v2.3.41/linux/include/asm-sparc64/parport.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/parport.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: parport.h,v 1.6 2000/01/09 15:16:34 ecd Exp $
+/* $Id: parport.h,v 1.7 2000/01/28 13:43:14 jj Exp $
  * parport.h: sparc64 specific parport initialization and dma.
  *
  * Copyright (C) 1999  Eddie C. Dost  (ecd@skynet.be)
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/sbus.h linux/include/asm-sparc64/sbus.h
--- v2.3.41/linux/include/asm-sparc64/sbus.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/sbus.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.12 1999/12/20 14:08:25 jj Exp $
+/* $Id: sbus.h,v 1.13 2000/01/28 13:43:14 jj Exp $
  * sbus.h: Defines for the Sun SBus.
  *
  * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/types.h linux/include/asm-sparc64/types.h
--- v2.3.41/linux/include/asm-sparc64/types.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/types.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: types.h,v 1.2 1997/12/22 13:28:33 mj Exp $ */
+/* $Id: types.h,v 1.3 2000/01/28 13:43:15 jj Exp $ */
 #ifndef _SPARC64_TYPES_H
 #define _SPARC64_TYPES_H
 
diff -u --recursive --new-file v2.3.41/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h
--- v2.3.41/linux/include/asm-sparc64/unistd.h	Fri Jan 28 15:09:09 2000
+++ linux/include/asm-sparc64/unistd.h	Mon Jan 31 23:37:19 2000
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.40 2000/01/16 06:20:38 davem Exp $ */
+/* $Id: unistd.h,v 1.42 2000/01/29 17:57:26 jj Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -161,7 +161,7 @@
 /* #define __NR_ni_syscall      143    ENOSYS under SunOS                          */
 #define __NR_getrlimit		144 /* Common                                      */
 #define __NR_setrlimit          145 /* Common                                      */
-/* #define __NR_killpg          146    SunOS Specific                              */
+#define __NR_pivot_root		146 /* Linux Specific, killpg under SunOS          */
 #define __NR_prctl		147 /* ENOSYS under SunOS                          */
 #define __NR_pciconfig_read	148 /* ENOSYS under SunOS                          */
 #define __NR_pciconfig_write	149 /* ENOSYS under SunOS                          */
diff -u --recursive --new-file v2.3.41/linux/include/linux/agp_backend.h linux/include/linux/agp_backend.h
--- v2.3.41/linux/include/linux/agp_backend.h	Tue Dec 14 01:27:24 1999
+++ linux/include/linux/agp_backend.h	Sat Jan 29 20:41:41 2000
@@ -94,6 +94,7 @@
 	unsigned long *memory;
 	off_t pg_start;
 	u32 type;
+	u32 physical;
 	u8 is_bound;
 	u8 is_flushed;
 } agp_memory;
diff -u --recursive --new-file v2.3.41/linux/include/linux/agpgart.h linux/include/linux/agpgart.h
--- v2.3.41/linux/include/linux/agpgart.h	Tue Dec 14 01:27:24 1999
+++ linux/include/linux/agpgart.h	Sat Jan 29 20:41:41 2000
@@ -92,6 +92,10 @@
 	int key;		/* tag of allocation            */
 	size_t pg_count;	/* number of pages              */
 	__u32 type;		/* 0 == normal, other devspec   */
+   	__u32 physical;         /* device specific (some devices  
+				 * need a phys address of the     
+				 * actual page behind the gatt    
+				 * table)                        */
 } agp_allocate;
 
 typedef struct _agp_bind {
@@ -160,6 +164,10 @@
 	int key;		/* tag of allocation            */
 	size_t pg_count;	/* number of pages              */
 	u32 type;		/* 0 == normal, other devspec   */
+	u32 physical;           /* device specific (some devices  
+				 * need a phys address of the     
+				 * actual page behind the gatt    
+				 * table)                        */
 } agp_allocate;
 
 typedef struct _agp_bind {
diff -u --recursive --new-file v2.3.41/linux/include/linux/auto_fs.h linux/include/linux/auto_fs.h
--- v2.3.41/linux/include/linux/auto_fs.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/auto_fs.h	Mon Jan 31 17:12:26 2000
@@ -20,8 +20,14 @@
 #include <linux/ioctl.h>
 #include <asm/types.h>
 
+/* This header file describes a range of autofs interface versions;
+   the new implementation ("autofs4") supports them all, but the old
+   implementation only supports v3.  */
 #define AUTOFS_MIN_PROTO_VERSION 3	/* Min version we support */
-#define AUTOFS_PROTO_VERSION 4		/* Current version */
+#define AUTOFS_MAX_PROTO_VERSION 4	/* Max (current) version */
+
+/* Backwards compat for autofs v3; it just implements a version */
+#define AUTOFS_PROTO_VERSION 3		/* v3 version */
 
 /*
  * Architectures where both 32- and 64-bit binaries can be executed
diff -u --recursive --new-file v2.3.41/linux/include/linux/i2c-dev.h linux/include/linux/i2c-dev.h
--- v2.3.41/linux/include/linux/i2c-dev.h	Tue Jan  4 13:57:21 2000
+++ linux/include/linux/i2c-dev.h	Fri Jan 28 19:36:23 2000
@@ -19,7 +19,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-/* $Id: i2c-dev.h,v 1.3 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-dev.h,v 1.6 2000/01/24 21:56:58 frodo Exp $ */
 
 #ifndef I2C_DEV_H
 #define I2C_DEV_H
@@ -33,10 +33,10 @@
 
 /* This is the structure as used in the I2C_SMBUS ioctl call */
 struct i2c_smbus_ioctl_data {
-  char read_write;
-  __u8 command;
-  int size;
-  union i2c_smbus_data *data;
+	char read_write;
+	__u8 command;
+	int size;
+	union i2c_smbus_data *data;
 };
 
 #ifndef __KERNEL__
@@ -46,79 +46,83 @@
 extern inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
                                      int size, union i2c_smbus_data *data)
 {
-  struct i2c_smbus_ioctl_data args;
+	struct i2c_smbus_ioctl_data args;
 
-  args.read_write = read_write;
-  args.command = command;
-  args.size = size;
-  args.data = data;
-  return ioctl(file,I2C_SMBUS,&args);
+	args.read_write = read_write;
+	args.command = command;
+	args.size = size;
+	args.data = data;
+	return ioctl(file,I2C_SMBUS,&args);
 }
 
 
 extern inline __s32 i2c_smbus_write_quick(int file, __u8 value)
 {
-  return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
+	return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
 }
-
+	
 extern inline __s32 i2c_smbus_read_byte(int file)
 {
-  union i2c_smbus_data data;
-  if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
-    return -1;
-  else
-    return 0x0FF & data.byte;
+	union i2c_smbus_data data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
+		return -1;
+	else
+		return 0x0FF & data.byte;
 }
 
 extern inline __s32 i2c_smbus_write_byte(int file, __u8 value)
 {
-  return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL);
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
+	                        I2C_SMBUS_BYTE,NULL);
 }
 
 extern inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
 {
-  union i2c_smbus_data data;
-  if (i2c_smbus_access(file,I2C_SMBUS_READ,command,I2C_SMBUS_BYTE_DATA,&data))
-    return -1;
-  else
-    return 0x0FF & data.byte;
+	union i2c_smbus_data data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_BYTE_DATA,&data))
+		return -1;
+	else
+		return 0x0FF & data.byte;
 }
 
 extern inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
                                               __u8 value)
 {
-  union i2c_smbus_data data;
-  data.byte = value;
-  return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_BYTE_DATA,
-                          &data);
+	union i2c_smbus_data data;
+	data.byte = value;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_BYTE_DATA, &data);
 }
 
 extern inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
 {
-  union i2c_smbus_data data;
-  if (i2c_smbus_access(file,I2C_SMBUS_READ,command,I2C_SMBUS_WORD_DATA,&data))
-    return -1;
-  else
-    return 0x0FFFF & data.word;
+	union i2c_smbus_data data;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_WORD_DATA,&data))
+		return -1;
+	else
+		return 0x0FFFF & data.word;
 }
 
 extern inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
                                               __u16 value)
 {
-  union i2c_smbus_data data;
-  data.word = value;
-  return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_WORD_DATA, 
-                          &data);
+	union i2c_smbus_data data;
+	data.word = value;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_WORD_DATA, &data);
 }
 
 extern inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
 {
-  union i2c_smbus_data data;
-  data.word = value;
-  if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_PROC_CALL,&data))
-    return -1;
-  else
-    return 0x0FFFF & data.word;
+	union i2c_smbus_data data;
+	data.word = value;
+	if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                     I2C_SMBUS_PROC_CALL,&data))
+		return -1;
+	else
+		return 0x0FFFF & data.word;
 }
 
 
@@ -126,29 +130,30 @@
 extern inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
                                               __u8 *values)
 {
-  union i2c_smbus_data data;
-  int i;
-  if (i2c_smbus_access(file,I2C_SMBUS_READ,command,I2C_SMBUS_BLOCK_DATA,&data))
-    return -1;
-  else {
-    for (i = 1; i <= data.block[0]; i++)
-      values[i-1] = data.block[i];
-    return data.block[0];
-  }
+	union i2c_smbus_data data;
+	int i;
+	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     I2C_SMBUS_BLOCK_DATA,&data))
+		return -1;
+	else {
+		for (i = 1; i <= data.block[0]; i++)
+			values[i-1] = data.block[i];
+			return data.block[0];
+	}
 }
 
 extern inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
                                                __u8 length, __u8 *values)
 {
-  union i2c_smbus_data data;
-  int i;
-  if (length > 32)
-    length = 32;
-  for (i = 1; i <= length; i++)
-    data.block[i] = values[i-1];
-  data.block[0] = length;
-  return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_BLOCK_DATA,
-                          &data);
+	union i2c_smbus_data data;
+	int i;
+	if (length > 32)
+		length = 32;
+	for (i = 1; i <= length; i++)
+		data.block[i] = values[i-1];
+	data.block[0] = length;
+	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+	                        I2C_SMBUS_BLOCK_DATA, &data);
 }
 
 #endif /* ndef __KERNEL__ */
diff -u --recursive --new-file v2.3.41/linux/include/linux/i2c-elektor.h linux/include/linux/i2c-elektor.h
--- v2.3.41/linux/include/linux/i2c-elektor.h	Tue Jan  4 13:57:21 2000
+++ linux/include/linux/i2c-elektor.h	Fri Jan 28 19:36:23 2000
@@ -22,7 +22,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
    Frodo Looijaard <frodol@dds.nl> */
 
-/* $Id: i2c-elektor.h,v 1.3 1999/12/21 23:45:58 frodo Exp $ */
+/* $Id: i2c-elektor.h,v 1.4 2000/01/18 23:54:07 frodo Exp $ */
 
 #ifndef I2C_PCF_ELEKTOR_H
 #define I2C_PCF_ELEKTOR_H 1
@@ -33,10 +33,10 @@
  */
 
 struct i2c_pcf_isa {
-   int pi_base;
-   int pi_irq;
-   int pi_clock;
-   int pi_own;
+	int pi_base;
+	int pi_irq;
+	int pi_clock;
+	int pi_own;
 };
 
 
diff -u --recursive --new-file v2.3.41/linux/include/linux/mmzone.h linux/include/linux/mmzone.h
--- v2.3.41/linux/include/linux/mmzone.h	Fri Jan  7 19:13:23 2000
+++ linux/include/linux/mmzone.h	Mon Jan 31 23:37:19 2000
@@ -12,13 +12,7 @@
  * Free memory management - zoned buddy allocator.
  */
 
-#if CONFIG_AP1000
-/* the AP+ needs to allocate 8MB contiguous, aligned chunks of ram
-   for the ring buffers */
-#define MAX_ORDER 12
-#else
 #define MAX_ORDER 10
-#endif
 
 typedef struct free_area_struct {
 	struct list_head free_list;
diff -u --recursive --new-file v2.3.41/linux/include/linux/nfsd/export.h linux/include/linux/nfsd/export.h
--- v2.3.41/linux/include/linux/nfsd/export.h	Wed Dec  8 14:11:28 1999
+++ linux/include/linux/nfsd/export.h	Mon Jan 31 17:12:02 2000
@@ -37,7 +37,8 @@
 #define NFSEXP_SUNSECURE	0x0100
 #define NFSEXP_CROSSMNT		0x0200
 #define NFSEXP_NOSUBTREECHECK	0x0400
-#define NFSEXP_ALLFLAGS		0x07FF
+#define	NFSEXP_NOAUTHNLM	0x0800		/* Don't authenticate NLM requests - just trust */
+#define NFSEXP_ALLFLAGS		0x0FFF
 
 
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.3.41/linux/include/linux/nfsd/nfsd.h linux/include/linux/nfsd/nfsd.h
--- v2.3.41/linux/include/linux/nfsd/nfsd.h	Tue Dec 14 01:27:24 1999
+++ linux/include/linux/nfsd/nfsd.h	Mon Jan 31 17:12:06 2000
@@ -35,8 +35,9 @@
 #define MAY_NOP			0
 #define MAY_SATTR		8
 #define MAY_TRUNC		16
-#if (MAY_SATTR | MAY_TRUNC) & (MAY_READ | MAY_WRITE | MAY_EXEC)
-# error "please use a different value for MAY_SATTR or MAY_TRUNC."
+#define MAY_LOCK		32
+#if (MAY_SATTR | MAY_TRUNC | MAY_LOCK) & (MAY_READ | MAY_WRITE | MAY_EXEC)
+# error "please use a different value for MAY_SATTR or MAY_TRUNC or MAY_LOCK."
 #endif
 #define MAY_CREATE		(MAY_EXEC|MAY_WRITE)
 #define MAY_REMOVE		(MAY_EXEC|MAY_WRITE|MAY_TRUNC)
diff -u --recursive --new-file v2.3.41/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.41/linux/include/linux/pci.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/pci.h	Mon Jan 31 17:11:47 2000
@@ -553,17 +553,17 @@
 _PCI_NOP_ALL(read, *)
 _PCI_NOP_ALL(write,)
 
-extern inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
+extern inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
 { return NULL; }
 
-extern inline struct pci_dev *pci_find_class(unsigned int class, struct pci_dev *from)
+extern inline struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from)
 { return NULL; }
 
 extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
 { return NULL; }
 
 extern inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device,
-unsigned int ss_vendor, unsigned int ss_device, struct pci_dev *from)
+unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from)
 { return NULL; }
 
 extern inline void pci_set_master(struct pci_dev *dev) { }
diff -u --recursive --new-file v2.3.41/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.41/linux/include/linux/proc_fs.h	Tue Jan 11 22:31:45 2000
+++ linux/include/linux/proc_fs.h	Mon Jan 31 23:37:19 2000
@@ -115,9 +115,6 @@
 extern struct inode_operations proc_sys_inode_operations;
 extern struct inode_operations proc_kcore_inode_operations;
 extern struct inode_operations proc_kmsg_inode_operations;
-#if CONFIG_AP1000
-extern struct inode_operations proc_ringbuf_inode_operations;
-#endif
 extern struct inode_operations proc_omirr_inode_operations;
 extern struct inode_operations proc_ppc_htab_inode_operations;
 
diff -u --recursive --new-file v2.3.41/linux/include/linux/qnx4_fs.h linux/include/linux/qnx4_fs.h
--- v2.3.41/linux/include/linux/qnx4_fs.h	Tue Jan 11 22:31:45 2000
+++ linux/include/linux/qnx4_fs.h	Mon Jan 31 15:40:23 2000
@@ -3,7 +3,7 @@
  *  Author                       : Richard Frowijn
  *  Function                     : qnx4 global filesystem definitions
  *  Version                      : 1.0.2
- *  Last modified                : 2000-01-06
+ *  Last modified                : 2000-01-31
  *
  *  History                      : 23-03-1998 created
  */
@@ -29,7 +29,9 @@
 #define QNX4_VALID_FS		0x0001	/* Clean fs. */
 #define QNX4_ERROR_FS		0x0002	/* fs has errors. */
 #define QNX4_BLOCK_SIZE         0x200	/* blocksize of 512 bytes */
-#define QNX4_DIR_ENTRY_SIZE     0x040	/* dir entry size */
+#define QNX4_BLOCK_SIZE_BITS    9	/* blocksize shift */
+#define QNX4_DIR_ENTRY_SIZE     0x040	/* dir entry size of 64 bytes */
+#define QNX4_DIR_ENTRY_SIZE_BITS 6	/* dir entry size shift */
 #define QNX4_XBLK_ENTRY_SIZE    0x200	/* xblk entry size */
 #define QNX4_INODES_PER_BLOCK   0x08	/* 512 / 64 */
 
@@ -96,7 +98,6 @@
 #endif
 
 extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
-extern unsigned long qnx4_count_free_inodes(struct super_block *sb);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 extern unsigned long qnx4_block_map(struct inode *inode, long iblock);
 
diff -u --recursive --new-file v2.3.41/linux/include/linux/serial.h linux/include/linux/serial.h
--- v2.3.41/linux/include/linux/serial.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/serial.h	Fri Jan 28 19:36:22 2000
@@ -10,6 +10,21 @@
 #ifndef _LINUX_SERIAL_H
 #define _LINUX_SERIAL_H
 
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+
+struct async_icount {
+	__u32	cts, dsr, rng, dcd, tx, rx;
+	__u32	frame, parity, overrun, brk;
+	__u32	buf_overrun;
+};
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
 struct serial_struct {
 	int	type;
 	int	line;
diff -u --recursive --new-file v2.3.41/linux/include/linux/serialP.h linux/include/linux/serialP.h
--- v2.3.41/linux/include/linux/serialP.h	Fri Jan 28 15:09:09 2000
+++ linux/include/linux/serialP.h	Mon Jan 31 17:12:48 2000
@@ -19,18 +19,10 @@
  * For definitions of the flags field, see tty.h
  */
 
+#include <linux/config.h>
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
-
-/*
- * Counters of the input lines (CTS, DSR, RI, CD) interrupts
- */
-struct async_icount {
-	__u32	cts, dsr, rng, dcd, tx, rx;
-	__u32	frame, parity, overrun, brk;
-	__u32	buf_overrun;
-};
 
 struct serial_state {
 	int	magic;
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/ircomm_tty.h linux/include/net/irda/ircomm_tty.h
--- v2.3.41/linux/include/net/irda/ircomm_tty.h	Wed Dec 29 13:13:21 1999
+++ linux/include/net/irda/ircomm_tty.h	Fri Jan 28 19:36:22 2000
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Jun  6 23:24:22 1999
- * Modified at:   Sun Dec 12 15:57:38 1999
+ * Modified at:   Fri Jan 28 13:16:57 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/irda.h linux/include/net/irda/irda.h
--- v2.3.41/linux/include/net/irda/irda.h	Fri Jan  7 19:13:23 2000
+++ linux/include/net/irda/irda.h	Mon Jan 31 17:12:37 2000
@@ -6,10 +6,10 @@
  * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Sat Dec 25 18:58:49 1999
+ * Modified at:   Fri Jan 28 13:16:32 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/irda_device.h linux/include/net/irda/irda_device.h
--- v2.3.41/linux/include/net/irda/irda_device.h	Wed Dec 29 13:13:21 1999
+++ linux/include/net/irda/irda_device.h	Mon Jan 31 17:11:31 2000
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Mon Dec 13 12:05:31 1999
+ * Modified at:   Fri Jan 14 10:46:56 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
  *     Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
  *
  *     This program is free software; you can redistribute it and/or 
@@ -121,23 +121,27 @@
 };
 
 /* Chip specific info */
-struct chipio_t {
-        int iobase, iobase2;  /* IO base */
-        int io_ext, io_ext2;  /* Length of iobase */
-	int membase;          /* Shared memory base */
+typedef struct {
+	int cfg_base;         /* Config register IO base */
+        int sir_base;         /* SIR IO base */
+	int fir_base;         /* FIR IO base */
+	int mem_base;         /* Shared memory base */
+        int sir_ext;          /* Length of SIR iobase */
+	int fir_ext;          /* Length of FIR iobase */
         int irq, irq2;        /* Interrupts used */
+        int dma, dma2;        /* DMA channel(s) used */
         int fifo_size;        /* FIFO size */
-
-        int dma, dma2;        /* DMA channel used */
         int irqflags;         /* interrupt flags (ie, SA_SHIRQ|SA_INTERRUPT) */
 	int direction;        /* Link direction, used by some FIR drivers */
-
+	int enabled;          /* Powered on? */
+	int suspended;        /* Suspended by APM */
 	__u32 speed;          /* Currently used speed */
+	__u32 new_speed;      /* Speed we must change to when Tx is finished */
 	int dongle_id;        /* Dongle or transceiver currently used */
-};
+} chipio_t;
 
 /* IO buffer specific info (inspired by struct sk_buff) */
-struct iobuff_t {
+typedef struct {
 	int state;            /* Receiving state (transmit state not used) */
 	int in_frame;         /* True if receiving frame */
 
@@ -148,7 +152,7 @@
 	int len;	      /* length of data */
 	int truesize;	      /* total size of buffer */
 	__u16 fcs;
-};
+} iobuff_t;
 
 /* Function prototypes */
 int  irda_device_init(void);
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/irmod.h linux/include/net/irda/irmod.h
--- v2.3.41/linux/include/net/irda/irmod.h	Sun Nov  7 16:37:34 1999
+++ linux/include/net/irda/irmod.h	Fri Jan 28 19:36:22 2000
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:58:52 1997
- * Modified at:   Sun Oct 31 20:01:17 1999
+ * Modified at:   Fri Jan 28 13:15:24 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  *
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/irport.h linux/include/net/irda/irport.h
--- v2.3.41/linux/include/net/irda/irport.h	Fri Jan  7 19:13:23 2000
+++ linux/include/net/irda/irport.h	Fri Jan 28 19:36:22 2000
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug  3 13:49:59 1997
- * Modified at:   Mon Jan  3 10:23:34 2000
+ * Modified at:   Fri Jan 14 10:21:10 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997, 1998-2000 Dag Brattli <dagb@cs.uit.no>
@@ -56,9 +56,9 @@
 
 	struct irlap_cb *irlap;    /* The link layer we are attached to */
 
-	struct chipio_t io;        /* IrDA controller information */
-	struct iobuff_t tx_buff;   /* Transmit buffer */
-	struct iobuff_t rx_buff;   /* Receive buffer */
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
 
 	struct qos_info qos;       /* QoS capabilities for this device */
 	dongle_t *dongle;          /* Dongle driver */
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/irtty.h linux/include/net/irda/irtty.h
--- v2.3.41/linux/include/net/irda/irtty.h	Wed Dec 29 13:13:21 1999
+++ linux/include/net/irda/irtty.h	Fri Jan 28 19:36:22 2000
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Sun Nov 21 21:19:35 1999
+ * Modified at:   Tue Jan 25 09:10:18 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  *  
- *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 1999-2000 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -55,15 +55,14 @@
 	struct tty_struct  *tty;
 	struct irlap_cb    *irlap; /* The link layer we are binded to */
 
-	struct chipio_t io;        /* IrDA controller information */
-	struct iobuff_t tx_buff;   /* Transmit buffer */
-	struct iobuff_t rx_buff;   /* Receive buffer */
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
 
 	struct qos_info qos;       /* QoS capabilities for this device */
 	dongle_t *dongle;          /* Dongle driver */
 
 	__u32 new_speed;
-
  	__u32 flags;               /* Interface flags */
 
 	INFRARED_MODE mode;
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/nsc-ircc.h linux/include/net/irda/nsc-ircc.h
--- v2.3.41/linux/include/net/irda/nsc-ircc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/nsc-ircc.h	Fri Jan 28 19:36:22 2000
@@ -0,0 +1,263 @@
+/*********************************************************************
+ *                
+ * Filename:      nsc-ircc.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Fri Nov 13 14:37:40 1998
+ * Modified at:   Sun Jan 23 17:47:00 2000
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
+ *     Copyright (c) 1998 Actisys Corp., www.actisys.com
+ *     All Rights Reserved
+ *      
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ *     Neither Dag Brattli nor University of Tromsř admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *     
+ ********************************************************************/
+
+#ifndef NSC_IRCC_H
+#define NSC_IRCC_H
+
+#include <linux/time.h>
+
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+/* DMA modes needed */
+#define DMA_TX_MODE     0x08    /* Mem to I/O, ++, demand. */
+#define DMA_RX_MODE     0x04    /* I/O to mem, ++, demand. */
+
+/* Config registers for the '108 */
+#define CFG_BAIC 0x00
+#define CFG_CSRT 0x01
+#define CFG_MCTL 0x02
+
+/* Config registers for the '338 */
+#define CFG_FER  0x00
+#define CFG_FAR  0x01
+#define CFG_PTR  0x02
+#define CFG_PNP0 0x1b
+#define CFG_PNP1 0x1c
+#define CFG_PNP3 0x4f
+
+/* Flags for configuration register CRF0 */
+#define APEDCRC		0x02
+#define ENBNKSEL	0x01
+
+/* Set 0 */
+#define TXD             0x00 /* Transmit data port */
+#define RXD             0x00 /* Receive data port */
+
+/* Register 1 */
+#define IER		0x01 /* Interrupt Enable Register*/
+#define IER_RXHDL_IE    0x01 /* Receiver high data level interrupt */
+#define IER_TXLDL_IE    0x02 /* Transeiver low data level interrupt */
+#define IER_LS_IE	0x04//* Link Status Interrupt */
+#define IER_ETXURI      0x04 /* Tx underrun */
+#define IER_DMA_IE	0x10 /* DMA finished interrupt */
+#define IER_TXEMP_IE    0x20
+#define IER_SFIF_IE     0x40 /* Frame status FIFO intr */
+#define IER_TMR_IE      0x80 /* Timer event */
+
+#define FCR		0x02 /* (write only) */
+#define FCR_FIFO_EN     0x01 /* Enable FIFO's */
+#define FCR_RXSR        0x02 /* Rx FIFO soft reset */
+#define FCR_TXSR        0x04 /* Tx FIFO soft reset */
+#define FCR_RXTH	0x40 /* Rx FIFO threshold (set to 16) */
+#define FCR_TXTH	0x20 /* Tx FIFO threshold (set to 17) */
+
+#define EIR		0x02 /* (read only) */
+#define EIR_RXHDL_EV	0x01
+#define EIR_TXLDL_EV    0x02
+#define EIR_LS_EV	0x04
+#define EIR_DMA_EV	0x10
+#define EIR_TXEMP_EV	0x20
+#define EIR_SFIF_EV     0x40
+#define EIR_TMR_EV      0x80
+
+#define LCR             0x03 /* Link control register */
+#define LCR_WLS_8       0x03 /* 8 bits */
+
+#define BSR 	        0x03 /* Bank select register */
+#define BSR_BKSE        0x80
+#define BANK0 	        LCR_WLS_8 /* Must make sure that we set 8N1 */
+#define BANK1	        0x80
+#define BANK2	        0xe0
+#define BANK3	        0xe4
+#define BANK4	        0xe8
+#define BANK5	        0xec
+#define BANK6	        0xf0
+#define BANK7     	0xf4
+
+#define MCR		0x04 /* Mode Control Register */
+#define MCR_MODE_MASK	~(0xd0)
+#define MCR_UART        0x00
+#define MCR_RESERVED  	0x20	
+#define MCR_SHARP_IR    0x40
+#define MCR_SIR         0x60
+#define MCR_MIR  	0x80
+#define MCR_FIR		0xa0
+#define MCR_CEIR        0xb0
+#define MCR_IR_PLS      0x10
+#define MCR_DMA_EN	0x04
+#define MCR_EN_IRQ	0x08
+#define MCR_TX_DFR	0x08
+
+#define LSR             0x05 /* Link status register */
+#define LSR_RXDA        0x01 /* Receiver data available */
+#define LSR_TXRDY       0x20 /* Transmitter ready */
+#define LSR_TXEMP       0x40 /* Transmitter empty */
+
+#define ASCR            0x07 /* Auxillary Status and Control Register */
+#define ASCR_RXF_TOUT   0x01 /* Rx FIFO timeout */
+#define ASCR_FEND_INF   0x02 /* Frame end bytes in rx FIFO */
+#define ASCR_S_EOT      0x04 /* Set end of transmission */
+#define ASCT_RXBSY      0x20 /* Rx busy */
+#define ASCR_TXUR       0x40 /* Transeiver underrun */
+#define ASCR_CTE        0x80 /* Clear timer event */
+
+/* Bank 2 */
+#define BGDL            0x00 /* Baud Generator Divisor Port (Low Byte) */
+#define BGDH            0x01 /* Baud Generator Divisor Port (High Byte) */
+
+#define ECR1		0x02 /* Extended Control Register 1 */
+#define ECR1_EXT_SL	0x01 /* Extended Mode Select */
+#define ECR1_DMANF	0x02 /* DMA Fairness */
+#define ECR1_DMATH      0x04 /* DMA Threshold */
+#define ECR1_DMASWP	0x08 /* DMA Swap */
+
+#define EXCR2		0x04
+#define EXCR2_TFSIZ	0x01 /* Rx FIFO size = 32 */
+#define EXCR2_RFSIZ	0x04 /* Tx FIFO size = 32 */
+
+#define TXFLV           0x06 /* Tx FIFO level */
+#define RXFLV           0x07 /* Rx FIFO level */
+
+/* Bank 3 */
+#define MID		0x00
+
+/* Bank 4 */
+#define TMRL            0x00 /* Timer low byte */
+#define TMRH            0x01 /* Timer high byte */
+#define IRCR1           0x02 /* Infrared control register 1 */
+#define IRCR1_TMR_EN    0x01 /* Timer enable */
+
+#define TFRLL		0x04
+#define TFRLH		0x05
+#define RFRLL		0x06
+#define RFRLH		0x07
+
+/* Bank 5 */
+#define IRCR2           0x04 /* Infrared control register 2 */
+#define IRCR2_MDRS      0x04 /* MIR data rate select */
+#define IRCR2_FEND_MD   0x20 /* */
+
+#define FRM_ST          0x05 /* Frame status FIFO */
+#define FRM_ST_VLD      0x80 /* Frame status FIFO data valid */
+#define FRM_ST_ERR_MSK  0x5f
+#define FRM_ST_LOST_FR  0x40 /* Frame lost */
+#define FRM_ST_MAX_LEN  0x10 /* Max frame len exceeded */
+#define FRM_ST_PHY_ERR  0x08 /* Physical layer error */
+#define FRM_ST_BAD_CRC  0x04 
+#define FRM_ST_OVR1     0x02 /* Rx FIFO overrun */
+#define FRM_ST_OVR2     0x01 /* Frame status FIFO overrun */
+
+#define RFLFL           0x06
+#define RFLFH           0x07
+
+/* Bank 6 */
+#define IR_CFG2		0x00
+#define IR_CFG2_DIS_CRC	0x02
+
+/* Bank 7 */
+#define IRM_CR		0x07 /* Infrared module control register */
+#define IRM_CR_IRX_MSL	0x40
+#define IRM_CR_AF_MNT   0x80 /* Automatic format */
+
+/* NSC chip information */
+struct nsc_chip {
+	char *name;          /* Name of chipset */
+	int cfg[3];          /* Config registers */
+	u_int8_t cid_index;  /* Chip identification index reg */
+	u_int8_t cid_value;  /* Chip identification expected value */
+	u_int8_t cid_mask;   /* Chip identification revision mask */
+
+	/* Functions for probing and initializing the specific chip */
+	int (*probe)(struct nsc_chip *chip, chipio_t *info);
+	int (*init)(struct nsc_chip *chip, chipio_t *info);
+};
+typedef struct nsc_chip nsc_chip_t;
+
+/* For storing entries in the status FIFO */
+struct st_fifo_entry {
+	int status;
+	int len;
+};
+
+#define MAX_TX_WINDOW 7
+#define MAX_RX_WINDOW 7
+
+struct st_fifo {
+	struct st_fifo_entry entries[MAX_RX_WINDOW];
+	int pending_bytes;
+	int head;
+	int tail;
+	int len;
+};
+
+struct frame_cb {
+	void *start; /* Start of frame in DMA mem */
+	int len;     /* Lenght of frame in DMA mem */
+};
+
+struct tx_fifo {
+	struct frame_cb queue[MAX_TX_WINDOW]; /* Info about frames in queue */
+	int             ptr;                  /* Currently being sent */
+	int             len;                  /* Lenght of queue */
+	int             free;                 /* Next free slot */
+	void           *tail;                 /* Next free start in DMA mem */
+};
+
+/* Private data for each instance */
+struct nsc_ircc_cb {
+	struct st_fifo st_fifo;    /* Info about received frames */
+	struct tx_fifo tx_fifo;    /* Info about frames to be transmitted */
+
+	struct net_device *netdev;     /* Yes! we are some kind of netdevice */
+	struct net_device_stats stats;
+	
+	struct irlap_cb *irlap;    /* The link layer we are binded to */
+	struct qos_info qos;       /* QoS capabilities for this device */
+	
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+
+	__u8 ier;                  /* Interrupt enable register */
+
+	struct timeval stamp;
+	struct timeval now;
+
+	spinlock_t lock;           /* For serializing operations */
+	
+	__u32 flags;               /* Interface flags */
+	__u32 new_speed;
+	int index;                 /* Instance index */
+};
+
+static inline void switch_bank(int iobase, int bank)
+{
+		outb(bank, iobase+BSR);
+}
+
+#endif /* NSC_IRCC_H */
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/nsc_fir.h linux/include/net/irda/nsc_fir.h
--- v2.3.41/linux/include/net/irda/nsc_fir.h	Fri Jan  7 19:13:23 2000
+++ linux/include/net/irda/nsc_fir.h	Wed Dec 31 16:00:00 1969
@@ -1,238 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      nsc_fir.h
- * Version:       
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Fri Nov 13 14:37:40 1998
- * Modified at:   Wed Jan  5 12:00:16 2000
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>
- *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
- *     Copyright (c) 1998 Actisys Corp., www.actisys.com
- *     All Rights Reserved
- *      
- *     This program is free software; you can redistribute it and/or 
- *     modify it under the terms of the GNU General Public License as 
- *     published by the Free Software Foundation; either version 2 of 
- *     the License, or (at your option) any later version.
- *  
- *     Neither Dag Brattli nor University of Tromsř admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef NSC_FIR_H
-#define NSC_FIR_H
-
-#include <linux/time.h>
-
-#include <linux/spinlock.h>
-#include <asm/io.h>
-
-#define PC87108         0x10
-#define PC97338         0xb0
-
-/* DMA modes needed */
-#define DMA_TX_MODE     0x08    /* Mem to I/O, ++, demand. */
-#define DMA_RX_MODE     0x04    /* I/O to mem, ++, demand. */
-
-/* Flags for configuration register CRF0 */
-#define APEDCRC		0x02
-#define ENBNKSEL	0x01
-
-/* Set 0 */
-#define TXD             0x00 /* Transmit data port */
-#define RXD             0x00 /* Receive data port */
-
-/* Register 1 */
-#define IER		0x01 /* Interrupt Enable Register*/
-#define IER_RXHDL_IE    0x01 /* Receiver high data level interrupt */
-#define IER_TXLDL_IE    0x02 /* Transeiver low data level interrupt */
-#define IER_LS_IE	0x04//* Link Status Interrupt */
-#define IER_ETXURI      0x04 /* Tx underrun */
-#define IER_DMA_IE	0x10 /* DMA finished interrupt */
-#define IER_TXEMP_IE    0x20
-#define IER_SFIF_IE     0x40 /* Frame status FIFO intr */
-#define IER_TMR_IE      0x80 /* Timer event */
-
-#define FCR		0x02 /* (write only) */
-#define FCR_FIFO_EN     0x01 /* Enable FIFO's */
-#define FCR_RXSR        0x02 /* Rx FIFO soft reset */
-#define FCR_TXSR        0x04 /* Tx FIFO soft reset */
-#define FCR_RXTH	0x40 /* Rx FIFO threshold (set to 16) */
-#define FCR_TXTH	0x20 /* Tx FIFO threshold (set to 17) */
-
-#define EIR		0x02 /* (read only) */
-#define EIR_RXHDL_EV	0x01
-#define EIR_TXLDL_EV    0x02
-#define EIR_LS_EV	0x04
-#define EIR_DMA_EV	0x10
-#define EIR_TXEMP_EV	0x20
-#define EIR_SFIF_EV     0x40
-#define EIR_TMR_EV      0x80
-
-#define LCR             0x03 /* Link control register */
-#define LCR_WLS_8       0x03 /* 8 bits */
-
-#define BSR 	        0x03 /* Bank select register */
-#define BSR_BKSE        0x80
-#define BANK0 	        LCR_WLS_8 /* Must make sure that we set 8N1 */
-#define BANK1	        0x80
-#define BANK2	        0xe0
-#define BANK3	        0xe4
-#define BANK4	        0xe8
-#define BANK5	        0xec
-#define BANK6	        0xf0
-#define BANK7     	0xf4
-
-#define MCR		0x04 /* Mode Control Register */
-#define MCR_MODE_MASK	~(0xd0)
-#define MCR_UART        0x00
-#define MCR_RESERVED  	0x20	
-#define MCR_SHARP_IR    0x40
-#define MCR_SIR         0x60
-#define MCR_MIR  	0x80
-#define MCR_FIR		0xa0
-#define MCR_CEIR        0xb0
-#define MCR_IR_PLS      0x10
-#define MCR_DMA_EN	0x04
-#define MCR_EN_IRQ	0x08
-#define MCR_TX_DFR	0x08
-
-#define LSR             0x05 /* Link status register */
-#define LSR_RXDA        0x01 /* Receiver data available */
-#define LSR_TXRDY       0x20 /* Transmitter ready */
-#define LSR_TXEMP       0x40 /* Transmitter empty */
-
-#define ASCR            0x07 /* Auxillary Status and Control Register */
-#define ASCR_RXF_TOUT   0x01 /* Rx FIFO timeout */
-#define ASCR_FEND_INF   0x02 /* Frame end bytes in rx FIFO */
-#define ASCR_S_EOT      0x04 /* Set end of transmission */
-#define ASCT_RXBSY      0x20 /* Rx busy */
-#define ASCR_TXUR       0x40 /* Transeiver underrun */
-#define ASCR_CTE        0x80 /* Clear timer event */
-
-/* Bank 2 */
-#define BGDL            0x00 /* Baud Generator Divisor Port (Low Byte) */
-#define BGDH            0x01 /* Baud Generator Divisor Port (High Byte) */
-
-#define ECR1		0x02 /* Extended Control Register 1 */
-#define ECR1_EXT_SL	0x01 /* Extended Mode Select */
-#define ECR1_DMANF	0x02 /* DMA Fairness */
-#define ECR1_DMATH      0x04 /* DMA Threshold */
-#define ECR1_DMASWP	0x08 /* DMA Swap */
-
-#define EXCR2		0x04
-#define EXCR2_TFSIZ	0x01 /* Rx FIFO size = 32 */
-#define EXCR2_RFSIZ	0x04 /* Tx FIFO size = 32 */
-
-#define TXFLV           0x06 /* Tx FIFO level */
-#define RXFLV           0x07 /* Rx FIFO level */
-
-/* Bank 3 */
-#define MID		0x00
-
-/* Bank 4 */
-#define TMRL            0x00 /* Timer low byte */
-#define TMRH            0x01 /* Timer high byte */
-#define IRCR1           0x02 /* Infrared control register 1 */
-#define IRCR1_TMR_EN    0x01 /* Timer enable */
-
-#define TFRLL		0x04
-#define TFRLH		0x05
-#define RFRLL		0x06
-#define RFRLH		0x07
-
-/* Bank 5 */
-#define IRCR2           0x04 /* Infrared control register 2 */
-#define IRCR2_MDRS      0x04 /* MIR data rate select */
-#define IRCR2_FEND_MD   0x20 /* */
-
-#define FRM_ST          0x05 /* Frame status FIFO */
-#define FRM_ST_VLD      0x80 /* Frame status FIFO data valid */
-#define FRM_ST_ERR_MSK  0x5f
-#define FRM_ST_LOST_FR  0x40 /* Frame lost */
-#define FRM_ST_MAX_LEN  0x10 /* Max frame len exceeded */
-#define FRM_ST_PHY_ERR  0x08 /* Physical layer error */
-#define FRM_ST_BAD_CRC  0x04 
-#define FRM_ST_OVR1     0x02 /* Rx FIFO overrun */
-#define FRM_ST_OVR2     0x01 /* Frame status FIFO overrun */
-
-#define RFLFL           0x06
-#define RFLFH           0x07
-
-/* Bank 6 */
-#define IR_CFG2		0x00
-#define IR_CFG2_DIS_CRC	0x02
-
-/* Bank 7 */
-#define IRM_CR		0x07 /* Infrared module control register */
-#define IRM_CR_IRX_MSL	0x40
-#define IRM_CR_AF_MNT   0x80 /* Automatic format */
-
-/* For storing entries in the status FIFO */
-struct st_fifo_entry {
-	int status;
-	int len;
-};
-
-struct st_fifo {
-	struct st_fifo_entry entries[10];
-	int head;
-	int tail;
-	int len;
-};
-
-struct frame_cb {
-	void *start; /* Start of frame in DMA mem */
-	int len;     /* Lenght of frame in DMA mem */
-};
-
-#define MAX_WINDOW 7
-
-struct tx_fifo {
-	struct frame_cb queue[MAX_WINDOW]; /* Info about frames in queue */
-	int             ptr;               /* Currently being sent */
-	int             len;               /* Lenght of queue */
-	int             free;              /* Next free slot */
-	void           *tail;              /* Next free start in DMA mem */
-};
-
-/* Private data for each instance */
-struct nsc_fir_cb {
-	struct st_fifo st_fifo;    /* Info about received frames */
-	struct tx_fifo tx_fifo;    /* Info about frames to be transmitted */
-
-	int tx_buff_offsets[10];   /* Offsets between frames in tx_buff */
-	int tx_len;                /* Number of frames in tx_buff */
-
-	struct net_device *netdev;     /* Yes! we are some kind of netdevice */
-	struct net_device_stats stats;
-	
-	struct irlap_cb *irlap;    /* The link layer we are binded to */
-	
-	struct chipio_t io;        /* IrDA controller information */
-	struct iobuff_t tx_buff;   /* Transmit buffer */
-	struct iobuff_t rx_buff;   /* Receive buffer */
-	struct qos_info qos;       /* QoS capabilities for this device */
-
-	struct timeval  stamp;
-	struct timeval  now;
-
-	spinlock_t lock;           /* For serializing operations */
-	
-	__u32 flags;               /* Interface flags */
-	__u32 new_speed;
-	int suspend;
-};
-
-static inline void switch_bank(int iobase, int bank)
-{
-		outb(bank, iobase+BSR);
-}
-
-#endif /* NSC_FIR_H */
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/smc-ircc.h linux/include/net/irda/smc-ircc.h
--- v2.3.41/linux/include/net/irda/smc-ircc.h	Fri Jan  7 19:13:23 2000
+++ linux/include/net/irda/smc-ircc.h	Fri Jan 28 19:36:22 2000
@@ -35,135 +35,142 @@
 #include <net/irda/irport.h>
 
 /* DMA modes needed */
-#define DMA_TX_MODE              0x08    /* Mem to I/O, ++, demand. */
-#define DMA_RX_MODE              0x04    /* I/O to mem, ++, demand. */
+#define DMA_TX_MODE                0x08    /* Mem to I/O, ++, demand. */
+#define DMA_RX_MODE                0x04    /* I/O to mem, ++, demand. */
 
-#define IRCC_MASTER              0x07
-#define IRCC_MASTER_POWERDOWN	 1<<7
-#define IRCC_MASTER_RESET        1<<6
-#define IRCC_MASTER_INT_EN       1<<5
-#define IRCC_MASTER_ERROR_RESET	 1<<4
+/* Master Control Register */
+#define IRCC_MASTER                0x07
+#define   IRCC_MASTER_POWERDOWN	   0x80
+#define   IRCC_MASTER_RESET        0x40
+#define   IRCC_MASTER_INT_EN       0x20
+#define   IRCC_MASTER_ERROR_RESET  0x10
 
 /* Register block 0 */
-#define IRCC_IIR                 0x01
-#define IRCC_IER                 0x02
-#define IRCC_LSR                 0x03
-#define IRCC_LCR_A               0x04
-#define IRCC_LCR_B               0x05
-#define IRCC_BSR                 0x06
-
-#define IRCC_IIR_ACTIVE_FRAME    1<<7
-#define IRCC_IIR_EOM             1<<6
-#define IRCC_IIR_RAW_MODE        1<<5
-#define IRCC_IIR_FIFO		 1<<4
-
-#define IRCC_IER_ACTIVE_FRAME	 1<<7
-#define IRCC_IER_EOM 		 1<<6
-#define IRCC_IER_RAW_MODE        1<<5
-#define IRCC_IER_FIFO		 1<<4
-
-#define IRCC_LSR_UNDERRUN        1<<7
-#define IRCC_LSR_OVERRUN         1<<6
-#define IRCC_LSR_FRAME_ERROR     1<<5
-#define IRCC_LSR_SIZE_ERROR      1<<4
-#define IRCC_LSR_CRC_ERROR       1<<3
-#define IRCC_LSR_FRAME_ABORT 	 1<<2
-
-#define IRCC_LCR_A_FIFO_RESET    1<<7
-#define IRCC_LCR_A_FAST          1<<6
-#define IRCC_LCR_A_GP_DATA       1<<5
-#define IRCC_LCR_A_RAW_TX        1<<4
-#define IRCC_LCR_A_RAW_RX        1<<3
-#define IRCC_LCR_A_ABORT         1<<2
-#define IRCC_LCR_A_DATA_DONE     1<<1
-
-#define IRCC_LCR_B_SCE_DISABLED  0x00<<6
-#define IRCC_LCR_B_SCE_TRANSMIT  0x01<<6
-#define IRCC_LCR_B_SCE_RECEIVE	 0x02<<6
-#define IRCC_LCR_B_SCE_UNDEFINED 0x03<<6
-#define IRCC_LCR_B_SIP_ENABLE	 1<<5
-#define IRCC_LCR_B_BRICK_WALL    1<<4
-
-#define IRCC_BSR_NOT_EMPTY	 1<<7
-#define IRCC_BSR_FIFO_FULL	 1<<6
-#define IRCC_BSR_TIMEOUT	 1<<5
+
+/* Interrupt Identification */
+#define IRCC_IIR                   0x01
+#define   IRCC_IIR_ACTIVE_FRAME    0x80
+#define   IRCC_IIR_EOM             0x40
+#define   IRCC_IIR_RAW_MODE        0x20
+#define   IRCC_IIR_FIFO		   0x10
+
+/* Interrupt Enable */
+#define IRCC_IER                   0x02
+#define   IRCC_IER_ACTIVE_FRAME	   0x80
+#define   IRCC_IER_EOM 		   0x40
+#define   IRCC_IER_RAW_MODE        0x20
+#define   IRCC_IER_FIFO		   0x10
+
+/* Line Status Register */
+#define IRCC_LSR                   0x03
+#define   IRCC_LSR_UNDERRUN        0x80
+#define   IRCC_LSR_OVERRUN         0x40
+#define   IRCC_LSR_FRAME_ERROR     0x20
+#define   IRCC_LSR_SIZE_ERROR      0x10
+#define   IRCC_LSR_CRC_ERROR       0x80
+#define   IRCC_LSR_FRAME_ABORT 	   0x40
+
+/* Line Control Register A */
+#define IRCC_LCR_A                 0x04
+#define   IRCC_LCR_A_FIFO_RESET    0x80
+#define   IRCC_LCR_A_FAST          0x40
+#define   IRCC_LCR_A_GP_DATA       0x20
+#define   IRCC_LCR_A_RAW_TX        0x10
+#define   IRCC_LCR_A_RAW_RX        0x08
+#define   IRCC_LCR_A_ABORT         0x04
+#define   IRCC_LCR_A_DATA_DONE     0x02
+
+/* Line Control Register B */
+#define IRCC_LCR_B                 0x05
+#define   IRCC_LCR_B_SCE_DISABLED  0x00
+#define   IRCC_LCR_B_SCE_TRANSMIT  0x40
+#define   IRCC_LCR_B_SCE_RECEIVE   0x80
+#define   IRCC_LCR_B_SCE_UNDEFINED 0xc0
+#define   IRCC_LCR_B_SIP_ENABLE	   0x20
+#define   IRCC_LCR_B_BRICK_WALL    0x10
+
+/* Bus Status Register */
+#define IRCC_BSR                   0x06
+#define   IRCC_BSR_NOT_EMPTY	   0x80
+#define   IRCC_BSR_FIFO_FULL	   0x40
+#define   IRCC_BSR_TIMEOUT	   0x20
 
 /* Register block 1 */
-#define IRCC_SCE_CFGA	         0x00
-#define IRCC_SCE_CFGB	         0x01
-#define IRCC_FIFO_THRESHOLD	 0x02
-
-#define IRCC_CFGA_AUX_IR	 0x01<<7
-#define IRCC_CFGA_HALF_DUPLEX	 0x01<<2
-#define IRCC_CFGA_TX_POLARITY	 0x01<<1
-#define IRCC_CFGA_RX_POLARITY	 0x01
-
-#define IRCC_CFGA_COM		 0x00<<3
-#define IRCC_CFGA_IRDA_SIR_A	 0x01<<3
-#define IRCC_CFGA_ASK_SIR	 0x02<<3
-#define IRCC_CFGA_IRDA_SIR_B	 0x03<<3
-#define IRCC_CFGA_IRDA_HDLC 	 0x04<<3
-#define IRCC_CFGA_IRDA_4PPM 	 0x05<<3
-#define IRCC_CFGA_CONSUMER	 0x06<<3
-#define IRCC_CFGA_RAW_IR	 0x07<<3
-#define IRCC_CFGA_OTHER		 0x08<<3
-
-#define IRCC_IR_HDLC             0x04
-#define IRCC_IR_4PPM             0x01
-#define IRCC_IR_CONSUMER         0x02
-
-#define IRCC_CFGB_LOOPBACK       0x01<<5
-#define IRCC_CFGB_LPBCK_TX_CRC	 0x01<<4
-#define IRCC_CFGB_NOWAIT	 0x01<<3
-#define IRCC_CFGB_STRING_MOVE	 0x01<<2
-#define IRCC_CFGB_DMA_BURST 	 0x01<<1
-#define IRCC_CFGB_DMA_ENABLE	 0x01
-
-#define IRCC_CFGB_COM		 0x00<<6
-#define IRCC_CFGB_IR		 0x01<<6
-#define IRCC_CFGB_AUX		 0x02<<6
-#define IRCC_CFGB_INACTIVE	 0x03<<6
+
+#define IRCC_FIFO_THRESHOLD	   0x02
+
+#define IRCC_SCE_CFGA	           0x00
+#define   IRCC_CFGA_AUX_IR	   0x80
+#define   IRCC_CFGA_HALF_DUPLEX	   0x04
+#define   IRCC_CFGA_TX_POLARITY	   0x02
+#define   IRCC_CFGA_RX_POLARITY	   0x01
+
+#define   IRCC_CFGA_COM		   0x00
+#define   IRCC_CFGA_IRDA_SIR_A	   0x08
+#define   IRCC_CFGA_ASK_SIR	   0x10
+#define   IRCC_CFGA_IRDA_SIR_B	   0x18
+#define   IRCC_CFGA_IRDA_HDLC 	   0x20
+#define   IRCC_CFGA_IRDA_4PPM 	   0x28
+#define   IRCC_CFGA_CONSUMER	   0x30
+#define   IRCC_CFGA_RAW_IR	   0x38
+#define   IRCC_CFGA_OTHER          0x40
+
+#define IRCC_IR_HDLC               0x04
+#define IRCC_IR_4PPM               0x01
+#define IRCC_IR_CONSUMER           0x02
+
+#define IRCC_SCE_CFGB	           0x01
+#define IRCC_CFGB_LOOPBACK         0x20
+#define IRCC_CFGB_LPBCK_TX_CRC	   0x10
+#define IRCC_CFGB_NOWAIT	   0x08
+#define IRCC_CFGB_STRING_MOVE	   0x04
+#define IRCC_CFGB_DMA_BURST 	   0x02
+#define IRCC_CFGB_DMA_ENABLE	   0x01
+
+#define IRCC_CFGB_MUX_COM          0x00
+#define IRCC_CFGB_MUX_IR           0x40
+#define IRCC_CFGB_MUX_AUX          0x80
+#define IRCC_CFGB_MUX_INACTIVE	   0xc0
 
 /* Register block 3 - Identification Registers! */
-#define IRCC_ID_HIGH	         0x00   /* 0x10 */
-#define IRCC_ID_LOW	         0x01   /* 0xB8 */
-#define IRCC_CHIP_ID 	         0x02   /* 0xF1 */
-#define IRCC_VERSION	         0x03   /* 0x01 */
-#define IRCC_INTERFACE	         0x04   /* low 4 = DMA, high 4 = IRQ */
+#define IRCC_ID_HIGH	           0x00   /* 0x10 */
+#define IRCC_ID_LOW	           0x01   /* 0xB8 */
+#define IRCC_CHIP_ID 	           0x02   /* 0xF1 */
+#define IRCC_VERSION	           0x03   /* 0x01 */
+#define IRCC_INTERFACE	           0x04   /* low 4 = DMA, high 4 = IRQ */
 
 /* Register block 4 - IrDA */
-#define IRCC_CONTROL             0x00
-#define IRCC_BOF_COUNT_LO        0x01
-#define IRCC_BRICKWALL_CNT_LO    0x02
-#define IRCC_BRICKWALL_TX_CNT_HI 0x03
-#define IRCC_TX_SIZE_LO          0x04
-#define IRCC_RX_SIZE_HI          0x05
-#define IRCC_RX_SIZE_LO          0x06
-
-#define IRCC_1152                0x01<<7
-#define IRCC_CRC                 0x01<<6
-
-/* For storing entries in the status FIFO */
-struct st_fifo_entry {
-	int status;
-	int len;
-};
-
-struct st_fifo {
-	struct st_fifo_entry entries[10];
-	int head;
-	int tail;
-	int len;
+#define IRCC_CONTROL               0x00
+#define IRCC_BOF_COUNT_LO          0x01 /* Low byte */
+#define IRCC_BOF_COUNT_HI          0x00 /* High nibble (bit 0-3) */
+#define IRCC_BRICKWALL_CNT_LO      0x02 /* Low byte */
+#define IRCC_BRICKWALL_CNT_HI      0x03 /* High nibble (bit 4-7) */
+#define IRCC_TX_SIZE_LO            0x04 /* Low byte */
+#define IRCC_TX_SIZE_HI            0x03 /* High nibble (bit 0-3) */
+#define IRCC_RX_SIZE_HI            0x05 /* High nibble (bit 0-3) */
+#define IRCC_RX_SIZE_LO            0x06 /* Low byte */
+
+#define IRCC_1152                  0x80
+#define IRCC_CRC                   0x40
+
+struct smc_chip {
+	char *name;
+	unsigned char entr1;
+	unsigned char entr2;
+	unsigned char cid_index;
+	unsigned char cid_value;
+	int (*probe)(struct smc_chip *chip, chipio_t *info);
 };
+typedef struct smc_chip smc_chip_t;
 
 /* Private data for each instance */
 struct ircc_cb {
-	struct net_device *netdev; /* Yes! we are some kind of netdevice */
+	struct net_device *netdev;     /* Yes! we are some kind of netdevice */
 	struct irlap_cb    *irlap; /* The link layer we are binded to */
 	
-	struct chipio_t io;        /* IrDA controller information */
-	struct iobuff_t tx_buff;   /* Transmit buffer */
-	struct iobuff_t rx_buff;   /* Receive buffer */
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
 
 	struct irport_cb *irport;
 
@@ -171,8 +178,6 @@
 	
 	__u32 new_speed;
 	__u32 flags;               /* Interface flags */
-
-	struct st_fifo st_fifo;
 
 	int tx_buff_offsets[10];   /* Offsets between frames in tx_buff */
 	int tx_len;                /* Number of frames in tx_buff */
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/toshoboe.h linux/include/net/irda/toshoboe.h
--- v2.3.41/linux/include/net/irda/toshoboe.h	Tue Nov 23 22:42:21 1999
+++ linux/include/net/irda/toshoboe.h	Fri Jan 28 19:36:22 2000
@@ -8,7 +8,7 @@
  * Author:        James McKenzie <james@fishsoup.dhs.org>
  * Created at:    Sat May 8  12:35:27 1999
  * 
- *     Copyright (c) 1999 James McKenzie, All Rights Reserved.
+ *     Copyright (c) 1999-2000 James McKenzie, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -23,22 +23,6 @@
  *
  ********************************************************************/
 
-/*
- * $Log: toshoboe.h,v $
- * Revision 1.4  1999/06/29 13:46:42  root
- * ls
- *
- * Revision 1.3  1999/06/29 12:31:03  root
- * *** empty log message ***
- *
- * Revision 1.2  1999/05/09 01:43:08  root
- * *** empty log message ***
- *
- * Revision 1.1  1999/05/09 01:25:58  root
- * Initial revision
- *
- */
-
 #ifndef TOSHOBOE_H
 #define TOSHOBOE_H
 
@@ -154,15 +138,15 @@
 
 struct toshoboe_cb
   {
-    struct net_device *netdev; /* Yes! we are some kind of netdevice */
+    struct net_device *netdev;      /* Yes! we are some kind of netdevice */
     struct net_device_stats stats;
 
-    struct irlap_cb    *irlap; /* The link layer we are binded to */
+    struct irlap_cb    *irlap;  /* The link layer we are binded to */
+    struct qos_info     qos;    /* QoS capabilities for this device */
 
-    struct chipio_t io;        /* IrDA controller information */
-    struct qos_info qos;       /* QoS capabilities for this device */
+    chipio_t io;                /* IrDA controller information */
 
-    __u32 flags;               /* Interface flags */
+    __u32 flags;                /* Interface flags */
     __u32 new_speed;
 
     struct pci_dev *pdev;       /*PCI device */
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/w83977af_ir.h linux/include/net/irda/w83977af_ir.h
--- v2.3.41/linux/include/net/irda/w83977af_ir.h	Tue Nov 23 22:42:21 1999
+++ linux/include/net/irda/w83977af_ir.h	Fri Jan 28 19:36:22 2000
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Thu Nov 19 13:55:34 1998
- * Modified at:   Mon Nov  8 10:00:40 1999
+ * Modified at:   Tue Jan 11 13:08:19 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-2000 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -174,11 +174,11 @@
 	struct net_device_stats stats;
 	
 	struct irlap_cb    *irlap; /* The link layer we are binded to */
+	struct qos_info     qos;   /* QoS capabilities for this device */
 	
-	struct chipio_t io;        /* IrDA controller information */
-	struct iobuff_t tx_buff;   /* Transmit buffer */
-	struct iobuff_t rx_buff;   /* Receive buffer */
-	struct qos_info qos;       /* QoS capabilities for this device */
+	chipio_t io;               /* IrDA controller information */
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
 	
 	__u32 flags;               /* Interface flags */
 	__u32 new_speed;
diff -u --recursive --new-file v2.3.41/linux/include/net/irda/wrapper.h linux/include/net/irda/wrapper.h
--- v2.3.41/linux/include/net/irda/wrapper.h	Wed Dec 29 13:13:21 1999
+++ linux/include/net/irda/wrapper.h	Fri Jan 28 19:36:22 2000
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Thu Nov  4 14:25:54 1999
+ * Modified at:   Tue Jan 11 12:37:29 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -55,6 +55,6 @@
 void async_bump(struct net_device *dev, struct net_device_stats *stats,
 		__u8 *buf, int len);
 void async_unwrap_char(struct net_device *dev, struct net_device_stats *stats,
-		       struct iobuff_t *buf, __u8 byte);
+		       iobuff_t *buf, __u8 byte);
 
 #endif
diff -u --recursive --new-file v2.3.41/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.41/linux/ipc/shm.c	Fri Jan 28 15:09:09 2000
+++ linux/ipc/shm.c	Sat Jan 29 20:39:52 2000
@@ -840,6 +840,15 @@
 	idx = (address - shmd->vm_start) >> PAGE_SHIFT;
 	idx += shmd->vm_pgoff;
 
+	/*
+	 * A shared mapping past the last page of the file is an error
+	 * and results in a SIGBUS, so logically a shared mapping past 
+	 * the end of a shared memory segment should result in SIGBUS
+	 * as well.
+	 */
+	if (idx >= shp->shm_npages) { 
+		return NULL;
+	}
 	down(&shp->sem);
 	if(shp != shm_lock(shp->id))
 		BUG();
diff -u --recursive --new-file v2.3.41/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.41/linux/kernel/exit.c	Fri Jan 28 15:09:09 2000
+++ linux/kernel/exit.c	Mon Jan 31 23:37:19 2000
@@ -405,9 +405,6 @@
 	task_lock(tsk);
 	sem_exit();
 	__exit_mm(tsk);
-#if CONFIG_AP1000
-	exit_msc(tsk);
-#endif
 	__exit_files(tsk);
 	__exit_fs(tsk);
 	__exit_sighand(tsk);
diff -u --recursive --new-file v2.3.41/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.3.41/linux/net/ax25/af_ax25.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ax25/af_ax25.c	Fri Jan 28 19:36:23 2000
@@ -1313,7 +1313,7 @@
 	int lv;
 	int addr_len = msg->msg_namelen;
 
-	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR))
+	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
 		return -EINVAL;
 
 	if (sk->zapped)
diff -u --recursive --new-file v2.3.41/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.3.41/linux/net/ipv4/ipconfig.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/ipconfig.c	Mon Jan 31 23:41:14 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.25 2000/01/09 02:19:31 davem Exp $
+ *  $Id: ipconfig.c,v 1.26 2000/01/29 07:42:08 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
diff -u --recursive --new-file v2.3.41/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.41/linux/net/ipv4/tcp.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/tcp.c	Mon Jan 31 23:41:14 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.160 2000/01/24 18:40:32 davem Exp $
+ * Version:	$Id: tcp.c,v 1.161 2000/01/31 01:21:16 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1119,7 +1119,7 @@
 
 	/* Delayed ACKs frequently hit locked sockets during bulk receive. */
 	time_to_ack = tp->ack.blocked && tp->ack.pending;
-#if 1/*def CONFIG_TCP_MORE_COARSE_ACKS*/
+#ifdef CONFIG_TCP_MORE_COARSE_ACKS
 	if (tp->ack.pending &&
 	    (tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss)
 		time_to_ack = 1;
@@ -1344,7 +1344,7 @@
 
 			tp->ucopy.len = len;
 
-			BUG_TRAP(tp->copied_seq == tp->rcv_nxt);
+			BUG_TRAP(tp->copied_seq == tp->rcv_nxt || (flags&MSG_PEEK));
 
 			/* Ugly... If prequeue is not empty, we have to
 			 * process it before releasing socket, otherwise
@@ -1408,7 +1408,7 @@
 					copied += chunk;
 				}
 			}
-#if 1/*def CONFIG_TCP_MORE_COARSE_ACKS*/
+#ifdef CONFIG_TCP_MORE_COARSE_ACKS
 			if (tp->ack.pending &&
 			    (tp->rcv_nxt - tp->rcv_wup) > tp->ack.rcv_mss)
 				tcp_send_ack(sk);
diff -u --recursive --new-file v2.3.41/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.3.41/linux/net/ipv4/tcp_input.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/tcp_input.c	Mon Jan 31 23:41:14 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.183 2000/01/24 18:40:33 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.186 2000/01/31 20:26:13 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1346,7 +1346,8 @@
 			goto kill_with_rst;
 
 		/* Dup ACK? */
-		if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt)) {
+		if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) ||
+		    TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) {
 			tcp_tw_put(tw);
 			return TCP_TW_SUCCESS;
 		}
@@ -1912,6 +1913,8 @@
 		    !tp->urg_data) {
 			int chunk = min(skb->len, tp->ucopy.len);
 
+			__set_current_state(TASK_RUNNING);
+
 			local_bh_enable();
 			if (memcpy_toiovec(tp->ucopy.iov, skb->data, chunk)) {
 				sk->err = EFAULT;
@@ -1948,10 +1951,9 @@
 		    !tp->urg_data)
 			tcp_fast_path_on(tp);
 
-		if (eaten)
+		if (eaten) {
 			kfree_skb(skb);
-
-		if (!sk->dead) {
+		} else if (!sk->dead) {
 			wake_up_interruptible(sk->sleep);
 			sock_wake_async(sk->socket,1, POLL_IN);
 		}
@@ -2296,29 +2298,7 @@
 	 *	  fails?						-ANK
 	 */
 
-	/* F.e. one possible tactics is: */
-	do {
-		u32 new_clamp = (tp->rcv_nxt-tp->copied_seq) + pruned;
-
-		/* This guy is not a good guy. I bet, he martirized cats,
-		 * when was child and grew up to finished sadist. Clamp him!
-		 */
-		if (new_clamp > 3*tp->ack.rcv_mss)
-			new_clamp -= tp->ack.rcv_mss;
-		else
-			new_clamp = 2*tp->ack.rcv_mss;
-		tp->window_clamp = min(tp->window_clamp, new_clamp);
-	} while (0);
-	/* Though it should be made earlier, when we are still not
-	 * congested. This header prediction logic sucks
-	 * without true implementation of VJ algorithm.
-	 * I am really anxious. How was it possible to combine
-	 * header prediction and sending ACKs outside of recvmsg() context?
-	 * They _are_ incompatible. We should not advance window so
-	 * brainlessly and we should not advertise so huge window from the very
-	 * beginning. BTW window "prediction" does not speedup anything!
-	 * SIlly, silly, silly.
-	 */
+	tp->ack.quick = 0;
 
 	if(atomic_read(&sk->rmem_alloc) < (sk->rcvbuf << 1))
 		return 0;
@@ -2525,10 +2505,14 @@
 
 				NET_INC_STATS_BH(TCPHPHitsToUser);
 
+				__set_current_state(TASK_RUNNING);
+
 				if (tcp_copy_to_iovec(sk, skb, tcp_header_len))
 					goto csum_error;
 
 				__skb_pull(skb,tcp_header_len);
+
+				tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 			} else {
 				if (tcp_checksum_complete_user(sk, skb))
 					goto csum_error;
@@ -2548,15 +2532,15 @@
 				 */
 				__skb_queue_tail(&sk->receive_queue, skb);
 				skb_set_owner_r(skb, sk);
-			}
 
-			tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+				tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
 
-			/* FIN bit check is not done since if FIN is set in
-			 * this frame, the pred_flags won't match up. -DaveM
-			 */
-			wake_up_interruptible(sk->sleep);
-			sock_wake_async(sk->socket,1, POLL_IN);
+				/* FIN bit check is not done since if FIN is set in
+				 * this frame, the pred_flags won't match up. -DaveM
+				 */
+				wake_up_interruptible(sk->sleep);
+				sock_wake_async(sk->socket,1, POLL_IN);
+			}
 
 			tcp_event_data_recv(tp, skb);
 
@@ -3467,7 +3451,8 @@
 					int tmo;
 
 					if (tp->linger2 < 0 ||
-					    after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
+					    (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
+					     after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt))) {
 						tcp_done(sk);
 						return 1;
 					}
@@ -3526,7 +3511,8 @@
 		 * BSD 4.4 also does reset.
 		 */
 		if (sk->shutdown & RCV_SHUTDOWN) {
-			if (after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
+			if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq &&
+			    after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) {
 				tcp_reset(sk);
 				return 1;
 			}
diff -u --recursive --new-file v2.3.41/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.3.41/linux/net/ipv4/tcp_ipv4.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/tcp_ipv4.c	Mon Jan 31 23:41:14 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.197 2000/01/21 06:37:28 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.198 2000/01/31 01:21:20 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -598,6 +598,7 @@
 
 	*skp = sk;
 	sk->pprev = skp;
+	sk->hashent = hash;
 	sock_prot_inc_use(sk->prot);
 	write_unlock_bh(&head->lock);
 
diff -u --recursive --new-file v2.3.41/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.3.41/linux/net/ipv4/tcp_output.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv4/tcp_output.c	Mon Jan 31 23:41:14 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.119 2000/01/19 04:06:15 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.120 2000/01/31 01:21:22 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1005,7 +1005,7 @@
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
 	/* Reserve space for headers. */
-	skb_reserve(buff, MAX_TCP_HEADER + 15);
+	skb_reserve(buff, MAX_TCP_HEADER);
 
 	/* We'll fix this up when we get a response from the other end.
 	 * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
diff -u --recursive --new-file v2.3.41/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c
--- v2.3.41/linux/net/ipv6/ipv6_sockglue.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv6/ipv6_sockglue.c	Mon Jan 31 23:41:14 2000
@@ -7,7 +7,7 @@
  *
  *	Based on linux/net/ipv4/ip_sockglue.c
  *
- *	$Id: ipv6_sockglue.c,v 1.31 2000/01/16 05:11:38 davem Exp $
+ *	$Id: ipv6_sockglue.c,v 1.32 2000/01/31 01:21:25 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -183,6 +183,7 @@
 				local_bh_enable();
 				sk->prot = &udp_prot;
 				sk->socket->ops = &inet_dgram_ops;
+				sk->family = PF_INET;
 			}
 			opt = xchg(&np->opt, NULL);
 			if (opt)
diff -u --recursive --new-file v2.3.41/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.3.41/linux/net/ipv6/tcp_ipv6.c	Fri Jan 28 15:09:09 2000
+++ linux/net/ipv6/tcp_ipv6.c	Mon Jan 31 23:41:14 2000
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.118 2000/01/18 08:24:22 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.119 2000/01/31 01:21:26 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -450,6 +450,7 @@
 
 	*skp = sk;
 	sk->pprev = skp;
+	sk->hashent = hash;
 	sock_prot_inc_use(sk->prot);
 	write_unlock_bh(&head->lock);
 
diff -u --recursive --new-file v2.3.41/linux/net/irda/irda_device.c linux/net/irda/irda_device.c
--- v2.3.41/linux/net/irda/irda_device.c	Fri Jan  7 19:13:23 2000
+++ linux/net/irda/irda_device.c	Fri Jan 28 19:36:22 2000
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Oct  9 09:22:27 1999
- * Modified at:   Wed Jan  5 14:17:16 2000
+ * Modified at:   Sun Jan 23 17:41:24 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
@@ -55,7 +55,8 @@
 #include <net/irda/wrapper.h>
 
 extern int irtty_init(void);
-extern int pc87108_init(void);
+extern int nsc_ircc_init(void);
+extern int ircc_init(void);
 extern int w83977af_init(void);
 extern int esi_init(void);
 extern int tekram_init(void);
@@ -121,7 +122,7 @@
 	w83977af_init();
 #endif
 #ifdef CONFIG_NSC_FIR
-	pc87108_init();
+	nsc_ircc_init();
 #endif
 #ifdef CONFIG_TOSHIBA_FIR
 	toshoboe_init();
@@ -143,9 +144,6 @@
 #endif
 #ifdef CONFIG_LITELINK_DONGLE
 	litelink_init();
-#endif
-#ifdef CONFIG_AIRPORT_DONGLE
- 	airport_init();
 #endif
 #ifdef CONFIG_OLD_BELKIN
  	old_belkin_init();
diff -u --recursive --new-file v2.3.41/linux/net/irda/wrapper.c linux/net/irda/wrapper.c
--- v2.3.41/linux/net/irda/wrapper.c	Wed Dec 29 13:13:21 1999
+++ linux/net/irda/wrapper.c	Fri Jan 28 19:36:22 2000
@@ -6,12 +6,12 @@
  * Status:        Stable
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Sun Dec 12 13:46:40 1999
+ * Modified at:   Fri Jan 28 13:21:09 2000
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Modified at:   Fri May 28  3:11 CST 1999
  * Modified by:   Horst von Brand <vonbrand@sleipnir.valparaiso.cl>
  * 
- *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -41,19 +41,19 @@
 
 static void state_outside_frame(struct net_device *dev, 
 				struct net_device_stats *stats, 
-				struct iobuff_t *rx_buff, __u8 byte);
+				iobuff_t *rx_buff, __u8 byte);
 static void state_begin_frame(struct net_device *dev, 
 			      struct net_device_stats *stats, 
-			      struct iobuff_t *rx_buff, __u8 byte);
+			      iobuff_t *rx_buff, __u8 byte);
 static void state_link_escape(struct net_device *dev, 
 			      struct net_device_stats *stats, 
-			      struct iobuff_t *rx_buff, __u8 byte);
+			      iobuff_t *rx_buff, __u8 byte);
 static void state_inside_frame(struct net_device *dev, 
 			       struct net_device_stats *stats, 
-			       struct iobuff_t *rx_buff, __u8 byte);
+			       iobuff_t *rx_buff, __u8 byte);
 
 static void (*state[])(struct net_device *dev, struct net_device_stats *stats, 
-		       struct iobuff_t *rx_buff, __u8 byte) = 
+		       iobuff_t *rx_buff, __u8 byte) = 
 { 
 	state_outside_frame,
 	state_begin_frame,
@@ -180,7 +180,7 @@
 		return;
 	}
 
-	/*  Align IP header to 20 bytes */
+	/* Align IP header to 20 bytes */
 	skb_reserve(skb, 1);
 	
         /* Copy data without CRC */
@@ -205,7 +205,7 @@
  */
 inline void async_unwrap_char(struct net_device *dev, 
 			      struct net_device_stats *stats, 
-			      struct iobuff_t *rx_buff, __u8 byte)
+			      iobuff_t *rx_buff, __u8 byte)
 {
 	(*state[rx_buff->state])(dev, stats, rx_buff, byte);
 }
@@ -218,7 +218,7 @@
  */
 static void state_outside_frame(struct net_device *dev, 
 				struct net_device_stats *stats, 
-				struct iobuff_t *rx_buff, __u8 byte)
+				iobuff_t *rx_buff, __u8 byte)
 {
 	switch (byte) {
 	case BOF:
@@ -245,7 +245,7 @@
  */
 static void state_begin_frame(struct net_device *dev, 
 			      struct net_device_stats *stats, 
-			      struct iobuff_t *rx_buff, __u8 byte)
+			      iobuff_t *rx_buff, __u8 byte)
 {
 	/* Time to initialize receive buffer */
 	rx_buff->data = rx_buff->head;
@@ -276,14 +276,14 @@
 }
 
 /*
- * Function state_link_escape (idev, byte)
+ * Function state_link_escape (dev, byte)
  *
  *    Found link escape character
  *
  */
 static void state_link_escape(struct net_device *dev, 
 			      struct net_device_stats *stats, 
-			      struct iobuff_t *rx_buff, __u8 byte)
+			      iobuff_t *rx_buff, __u8 byte)
 {
 	switch (byte) {
 	case BOF: /* New frame? */
@@ -315,14 +315,14 @@
 }
 
 /*
- * Function state_inside_frame (idev, byte)
+ * Function state_inside_frame (dev, byte)
  *
  *    Handle bytes received within a frame
  *
  */
 static void state_inside_frame(struct net_device *dev, 
 			       struct net_device_stats *stats,
-			       struct iobuff_t *rx_buff, __u8 byte)
+			       iobuff_t *rx_buff, __u8 byte)
 {
 	int ret = 0; 
 
diff -u --recursive --new-file v2.3.41/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.3.41/linux/net/netrom/af_netrom.c	Fri Jan 28 15:09:09 2000
+++ linux/net/netrom/af_netrom.c	Fri Jan 28 19:36:23 2000
@@ -978,7 +978,7 @@
 	unsigned char *asmptr;
 	int size;
 
-	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR))
+	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
 		return -EINVAL;
 
 	if (sk->zapped)
diff -u --recursive --new-file v2.3.41/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.3.41/linux/net/rose/af_rose.c	Fri Jan 28 15:09:09 2000
+++ linux/net/rose/af_rose.c	Fri Jan 28 19:36:23 2000
@@ -1010,7 +1010,7 @@
 	unsigned char *asmptr;
 	int n, size, qbit = 0;
 
-	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_OOB|MSG_EOR))
+	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
 		return -EINVAL;
 
 	if (sk->zapped)
diff -u --recursive --new-file v2.3.41/linux/net/sched/sch_dsmark.c linux/net/sched/sch_dsmark.c
--- v2.3.41/linux/net/sched/sch_dsmark.c	Fri Jan  7 19:13:23 2000
+++ linux/net/sched/sch_dsmark.c	Mon Jan 31 23:41:14 2000
@@ -1,6 +1,6 @@
 /* net/sched/sch_dsmark.c - Differentiated Services field marker */
 
-/* Written 1998,1999 by Werner Almesberger, EPFL ICA */
+/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
 
 
 #include <linux/config.h>
@@ -82,7 +82,7 @@
 
 static unsigned long dsmark_get(struct Qdisc *sch,u32 classid)
 {
-	struct dsmark_qdisc_data *p = PRIV(sch);
+	struct dsmark_qdisc_data *p __attribute__((unused)) = PRIV(sch);
 
 	DPRINTK("dsmark_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid);
 	return TC_H_MIN(classid)+1;
diff -u --recursive --new-file v2.3.41/linux/net/sched/sch_gred.c linux/net/sched/sch_gred.c
--- v2.3.41/linux/net/sched/sch_gred.c	Fri Jan  7 19:13:23 2000
+++ linux/net/sched/sch_gred.c	Mon Jan 31 23:41:14 2000
@@ -10,9 +10,10 @@
  * Authors:    J Hadi Salim (hadi@nortelnetworks.com) 1998,1999
  *
  *             991129: -  Bug fix with grio mode
- *		       - a better sing. AvgQ mode with Grio
+ *		       - a better sing. AvgQ mode with Grio(WRED)
  *		       - A finer grained VQ dequeue based on sugestion
  *		         from Ren Liu
+ *		       - More error checks
  *
  *
  *
@@ -134,17 +135,10 @@
 	    "general backlog %d\n",skb->tc_index&0xf,sch->handle,q->backlog,
 	    sch->stats.backlog);
 	/* sum up all the qaves of prios <= to ours to get the new qave*/
-	if (t->grio) {
+	if (!t->eqp && t->grio) {
 		for (i=0;i<t->DPs;i++) {
 			if ((!t->tab[i]) || (i==q->DP))	
 				continue; 
-			if (t->tab[i]->prio == q->prio ){
-				qave=0;
-				t->eqp=1;
-				q->qave=t->tab[t->def]->qave;
-				q->qidlestart=t->tab[t->def]->qidlestart;
-				break;
-			}
 				
 			if ((t->tab[i]->prio < q->prio) && (PSCHED_IS_PASTPERFECT(t->tab[i]->qidlestart)))
 				qave +=t->tab[i]->qave;
@@ -155,6 +149,12 @@
         q->packetsin++;
         q->bytesin+=skb->len;
 
+	if (t->eqp && t->grio) {
+		qave=0;
+		q->qave=t->tab[t->def]->qave;
+		q->qidlestart=t->tab[t->def]->qidlestart;
+	}
+
 	if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) {
 		long us_idle;
 		PSCHED_GET_TIME(now);
@@ -163,7 +163,12 @@
 
 		q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF];
 	} else {
-		q->qave += q->backlog - (q->qave >> q->Wlog);
+		if (t->eqp) {
+			q->qave += sch->stats.backlog - (q->qave >> q->Wlog);
+		} else {
+			q->qave += q->backlog - (q->qave >> q->Wlog);
+		}
+
 	}
 	
 
@@ -232,18 +237,22 @@
 
 	skb = __skb_dequeue(&sch->q);
 	if (skb) {
-		q= t->tab[(skb->tc_index&0xf)];
 		sch->stats.backlog -= skb->len;
-		q->backlog -= skb->len;
-		if (!q->backlog && !t->eqp)
-			PSCHED_GET_TIME(q->qidlestart);
+		q= t->tab[(skb->tc_index&0xf)];
+		if (q) {
+			q->backlog -= skb->len;
+			if (!q->backlog && !t->eqp)
+				PSCHED_GET_TIME(q->qidlestart);
+		} else {
+			D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); 
+		}
 		return skb;
 	}
 
 	if (t->eqp) {
 			q= t->tab[t->def];
 			if (!q)	
-				printk("no default VQ set: Results will be "
+				D2PRINTK("no default VQ set: Results will be "
 				       "screwed up\n");
 			else
 				PSCHED_GET_TIME(q->qidlestart);
@@ -256,31 +265,37 @@
 gred_drop(struct Qdisc* sch)
 {
 	struct sk_buff *skb;
-	int i;
 
 	struct gred_sched_data *q;
 	struct gred_sched *t= (struct gred_sched *)sch->data;
 
 	skb = __skb_dequeue_tail(&sch->q);
 	if (skb) {
-		q= t->tab[(skb->tc_index&0xf)];
 		sch->stats.backlog -= skb->len;
 		sch->stats.drops++;
-		q->backlog -= skb->len;
-		q->other++;
+		q= t->tab[(skb->tc_index&0xf)];
+		if (q) {
+			q->backlog -= skb->len;
+			q->other++;
+			if (!q->backlog && !t->eqp)
+				PSCHED_GET_TIME(q->qidlestart);
+			} else {
+				D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); 
+			}
+
 		kfree_skb(skb);
 		return 1;
 	}
 
-/* could probably do it for a single VQ before freeing the skb */
-        for (i=0;i<t->DPs;i++) {
-	        q= t->tab[i];
-		if (!q)	
-			continue; 
-        	PSCHED_GET_TIME(q->qidlestart);
-        }
+	q=t->tab[t->def];
+	if (!q) {
+		D2PRINTK("no default VQ set: Results might be screwed up\n");
+		return 0;
+	}
 
+	PSCHED_GET_TIME(q->qidlestart);
 	return 0;
+
 }
 
 static void gred_reset(struct Qdisc* sch)
@@ -295,7 +310,6 @@
 		kfree_skb(skb);
 	sch->stats.backlog = 0;
 
-/* could probably do it for a single VQ before freeing the skb */
         for (i=0;i<t->DPs;i++) {
 	        q= t->tab[i];
 		if (!q)	
@@ -319,6 +333,7 @@
         struct tc_gred_sopt *sopt;
         struct rtattr *tb[TCA_GRED_STAB];
         struct rtattr *tb2[TCA_GRED_STAB];
+	int i;
 
         if (opt == NULL ||
             rtattr_parse(tb, TCA_GRED_STAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) )
@@ -340,13 +355,13 @@
 	    }
 
 
-            if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 ||
+	if (!table->DPs || tb[TCA_GRED_PARMS-1] == 0 || tb[TCA_GRED_STAB-1] == 0 ||
 		RTA_PAYLOAD(tb[TCA_GRED_PARMS-1]) < sizeof(*ctl) ||
 		RTA_PAYLOAD(tb[TCA_GRED_STAB-1]) < 256)
-                return -EINVAL;
+			return -EINVAL;
 
-        ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]);
-        if (ctl->DP > MAX_DPs-1 || ctl->DP <0) {
+	ctl = RTA_DATA(tb[TCA_GRED_PARMS-1]);
+	if (ctl->DP > MAX_DPs-1 || ctl->DP <0) {
 		/* misbehaving is punished! Put in the default drop probability */
 		DPRINTK("\nGRED: DP %u not in  the proper range fixed. New DP "
 			"set to default at %d\n",ctl->DP,table->def);
@@ -356,8 +371,8 @@
 	if (table->tab[ctl->DP] == NULL) {
 		table->tab[ctl->DP]=kmalloc(sizeof(struct gred_sched_data),
 					    GFP_KERNEL);
-	        memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data)));
-        }
+		memset(table->tab[ctl->DP], 0, (sizeof(struct gred_sched_data)));
+	}
 	q= table->tab[ctl->DP]; 
 
 	if (table->grio) {
@@ -399,6 +414,19 @@
 
 	PSCHED_SET_PASTPERFECT(q->qidlestart);
 	memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
+
+	if ( table->initd && table->grio) {
+	/* this looks ugly but its not in the fast path */
+		for (i=0;i<table->DPs;i++) {
+			if ((!table->tab[i]) || (i==q->DP) )    
+				continue; 
+			if (table->tab[i]->prio == q->prio ){
+				/* WRED mode detected */
+				table->eqp=1;
+				break;
+			}
+		}
+	}
 
 	if (!table->initd) {
 		table->initd=1;
